论坛首页 Java企业应用论坛

关于Java运行时数据区的内存分配问题(求解惑)

浏览 9374 次
精华帖 (0) :: 良好帖 (5) :: 新手帖 (0) :: 隐藏帖 (0)
作者 正文
   发表时间:2011-04-09  
public class MemoryAllocation {

	int x = 10;
	
	String str = "java";
	
	int maxMemory = 1024;
	
	static final int ID = 101;
	
	static final String NAME = "javaeye";
	
	MemoryAllocation(int maxMemory) {
		this.maxMemory = maxMemory;
	}

	public static void main(String[] args) {
		String s = new String("java");
		int y = 10;
		MemoryAllocation ma = new MemoryAllocation(2048);
		/*
			例如:从进入main方法开始,执行“String s = new String("java");”语句。
			Java虚拟机把String类的类型信息存入method area。
			找到String类,在heap区为新的String实例分配内存,该实例持有指向method area区String类的类型信息。
			将局部变量s存储在main线程方法调用栈中压入的新帧中,s变量指向heap区中的String实例。
		*/
	}

}

想问下执行到“int y = 10;”语句时,main线程方法调用栈中会压入一个新帧么?如果不会,局部变量y是怎么存储的?
以及执行完“MemoryAllocation ma = new MemoryAllocation(2048);”语句时,数据具体是怎样分配在内存中的?
   发表时间:2011-04-09   最后修改:2011-04-09
asheng 写道
想问下执行到“int y = 10;”语句时,main线程方法调用栈中会压入一个新帧么?

方法调用栈的名字听起来比较奇怪,一般是叫Java栈(JVMS1里面的叫法)或者Java虚拟机栈(JVMS2、3里面的叫法)
既然你都称呼它为“方法调用栈”了,那自然是发生方法调用的时候才会有新的stackframe入栈。

asheng 写道
如果不会,局部变量y是怎么存储的?

存储在栈帧的局部变量表中,在main方法编译的时候,编译器就已经计算好需要多大的局部变量表,并存储于方法的Code属性的属性表中,你用javap -verbose命令看看,在方法名称下面会输出这个方法所需要的局部变量表和操作数栈的大小,这些都是编译期算好的。

asheng 写道
执行完“MemoryAllocation ma = new MemoryAllocation(2048);”语句时,数据具体是怎样分配在内存中的?

这个问题稍微麻烦一些,由于JVMS中是不描述具体的内存布局的,这些允许各个虚拟机实现自己来把握,所以回答这个问题必须再加个限定语:“在某种虚拟机中”。
譬如在HotSpot VM中,“MemoryAllocation ma = new MemoryAllocation(2048)”这句话反应到内存中,首先在main方法的栈帧中有一个reference指向后面heap中的MemoryAllocation对象。如果是32位的HotSpot,这个它占用的空间是32bit,如果是64位的HotSpot,就要取决于是否打开了指针压缩优化,占用32-64bit不等。然后MemoryAllocation对象分配在heap中,首先有一个对象头,包括了MarkWord和一个指向对象所属类元数据的指针,如果是32位HotSpot,就是32bit+32bit,64位HotSpot的话则翻倍。接下来就是存放具体数据了,只存放int x、String str、int MaxMemory这3项数据,后面的static final int ID、static final String NAME是不会放在对象实例中的。这3个数据正好都是4字节长度,不过由于GC实现原因,Object的大小必须是8的倍数,所以还要放4直接空白进去占个位置……至于你把int MaxMemory赋值为2048,对内存空间占用是木有影响的。

嗯……大致就是这样。
0 请登录后投票
   发表时间:2011-04-09  
引用
首先有一个对象头,包括了MarkWord和一个指向对象所属类元数据的指针,


这里面的 MarkWord 和 一个指向对象所属元数据的指针是什么? 这个指针具体的作用是什么?
0 请登录后投票
   发表时间:2011-04-09   最后修改:2011-04-09
qwe_rt 写道
引用
首先有一个对象头,包括了MarkWord和一个指向对象所属类元数据的指针,


这里面的 MarkWord 和 一个指向对象所属元数据的指针是什么? 这个指针具体的作用是什么?


markword并不存储固定的数据,为了尽量在非常有限的空间中存储尽量多的信息,它是根据状态位在不同状态下存储不同的内容的。通常状态下(未锁定状态),存了诸如hashcode、gc年龄等内容,其他的状态(轻量级锁锁、重量级锁定、可偏向、GCMark)还存了不同的东西。具体你可参考一下下面这个片段的内容:



至于那个指针,因为HotSpot的找一个对象是直接指针定位,而非句柄定位。所以找到对象后,在对象数据中必须有途径能找到这个对象所属类的信息,这个指针就这样出现咯。
  • 大小: 39.8 KB
0 请登录后投票
   发表时间:2011-04-09  
这里讲到了轻量级锁,重量级锁 , 这个“锁” 应该 说的是 对象锁 。 比如一个对象 存在锁,其他线程必须等待 其 释放锁 后才能使用该对象 , 比如用synchronized(this){ ...} 给对象加锁 。

======
不明白的地方在于:这里的锁 有 轻量级 和重量级 区分 。  什么情况下对象锁是重量级的,什么情况对象锁是轻量级的 。
0 请登录后投票
   发表时间:2011-04-09  
Anddy 写道
这里讲到了轻量级锁,重量级锁 , 这个“锁” 应该 说的是 对象锁 。 比如一个对象 存在锁,其他线程必须等待 其 释放锁 后才能使用该对象 , 比如用synchronized(this){ ...} 给对象加锁 。

======
不明白的地方在于:这里的锁 有 轻量级 和重量级 区分 。  什么情况下对象锁是重量级的,什么情况对象锁是轻量级的 。


那把上面那个片段的前面也贴出来回答你这个问题。


  • 大小: 9.7 KB
0 请登录后投票
   发表时间:2011-04-10  
分析得很精辟啊。。学习了
0 请登录后投票
   发表时间:2011-04-10  
Synchronized 修饰的为重量级锁,Lock级别的为轻量级的锁
0 请登录后投票
   发表时间:2011-04-10  
jobar 写道
Synchronized 修饰的为重量级锁,Lock级别的为轻量级的锁





按照上面最后一句话的提示,应该可以这样理解:  在存在多线程竞争的情况下, 应该使用的重量级 锁 ; 在不存在多线程竞争的情况【比如线程同步的情况下】下 , 可能使用轻量级锁也可能使用重量级锁   。  

不知道我理解是否到位。 对于 “Synchronized 修饰的为重量级锁”  可以理解为 重量级锁 【我不确定是否一定是重量级锁】 。

“Lock级别 的为轻量级的锁”  这个 不一定吧 !
0 请登录后投票
   发表时间:2011-04-10   最后修改:2011-04-10
首先不要混淆了概念。
重量级的锁是指使用操作系统提供的互斥量保证共享数据在多线程竞争时被串行访问。
轻量级的锁是指在没有多线程竞争时,让虚拟机不去动用操作系统的互斥量,而改为使用对象的MarkWord和线程的LockRecord来标识共享数据正在被某个线程访问,这个标识操作是通过CAS来完成的。只要没有其他线程再进来,那轻量级锁就成功节省了一些性能开销。但如果有其他线程进来,那轻量级锁就要失效掉,膨胀回重量级锁来完成阻塞同步,这种场景下轻量级锁实际是比直接一开始就用重量级锁更加慢的(多了CAS的开销)。

因此重量级锁还是轻量级锁,与采用synchronized还是j.u.c的lock没有什么联系,至少是完全不构成因果关系的。

而lightweight lock从“使用”的角度讲,程序员基本不需要选择(没法选择),也不需要太过关心,那些都是JVM的活。简单地说,基于互斥量的重量锁实际是一种悲观的并发策略,无论是否有竞争都先去加锁。而基于CAS的轻量锁则是一种乐观的并发策略,它先假设不会出现竞争,当真正出现竞争时再采取补救措施(膨胀)。因此在总是有竞争的场景下,重量级锁更快,在大多数情况都不出现竞争的场景下,轻量级锁会快一些;一般应用都是后者多于前者的,所以JVM(SunJDK1.6+)默认开着轻量级锁。

这样的解释能解答楼上的疑问了吗?
3 请登录后投票
论坛首页 Java企业应用版

跳转论坛:
Global site tag (gtag.js) - Google Analytics