JVM 深入理解(一) 结构与内存管理

2019-06-11  本文已影响0人  莫库施勒

JVM 运行时数据区

JVM 运行时数据区

对象访问

Object obj=new Object();

在这句代码上,Object obj这部分语义会反映到Java栈栈帧的本地变量表中,作为一个reference类型数据出现.
new Object()这局会反映到Java堆中,形成一块存储了object类型所有实例数据值(Instance Data,对象中各个实例字段的数据)的结构化内存,根据具体类型以及虚拟机的实现的对象内存布局的不从,这块内存的长度是不固定的。另外,在Java堆中还必须包含能查找到此类型数据的地址信息,这些类型数据则存储在方法区中。

主流的访问方式有两种:使用句柄和直接指针。

垃圾回收算法

内存分配机制

Java内存分配和回收的机制概括的说,就是分代分配,分代回收。对象将根据存活的时间被分为:

这种垃圾回收的方式就是著名的“停止-复制(Stop-and-copy)”清理法(将Eden区和一个Survivor中仍然存活的对象拷贝到另一个Survivor中),这不代表着停止复制清理法很高效,其实,它也只在这种情况下高效。

在Eden区,HotSpot虚拟机使用了两种技术来加快内存分配。分别是bump-the-pointer和TLAB(Thread-Local Allocation Buffers),这两种技术的做法分别是:由于Eden区是连续的,因此bump-the-pointer技术的核心就是跟踪最后创建的一个对象,在对象创建时,只需要检查最后一个对象后面是否有足够的内存即可,从而大大加快内存分配速度;而对于TLAB技术是对于多线程而言的,将Eden区分为若干段,每个线程使用独立的一段,避免相互影响。TLAB结合bump-the-pointer技术,将保证每个线程都使用Eden区的一段,并快速的分配内存。

内存回收

上面已经说了年轻代是停止-复制算法。一般,老年代用的算法是标记-整理算法,即:标记出仍然存活的对象(存在引用的),将所有存活的对象向一端移动,以保证内存的连续。

在发生Minor GC时,虚拟机会检查每次晋升进入老年代的大小是否大于老年代的剩余空间大小,如果大于,则直接触发一次Full GC,否则,就查看是否设置了-XX:+HandlePromotionFailure(允许担保失败),如果允许,则只会进行MinorGC,此时可以容忍内存分配失败;如果不允许,则仍然进行Full GC(这代表着如果设置-XX:+Handle PromotionFailure,则触发MinorGC就会同时触发Full GC,哪怕老年代还有很多内存,所以,最好不要这样做)

永久代的回收有两种:常量池中的常量,无用的类信息,常量的回收很简单,没有引用了就可以被回收。

上一篇下一篇

猜你喜欢

热点阅读