《深入理解JAVA虚拟机》阅读笔记之自动内存管理机制

正是由于JAVA将内存的的控制权交给虚拟机,一旦出现内存泄露或溢出方面的问题,如果不了解虚拟机是怎样工作的,那么排查错误将是一件非常艰难的工作。


一、从概念上理解运行时数据区域(作用、服务对象、可能产生的问题、问题示例等)


JAVA将内存分为几个数据区域,这几个区域的作用各不相同。他们的创建与销毁的时间也不尽相同。JAVA虚拟机规范中规定的几个数据区域如下:


1、程序计数器

学过《计算机组成原理》的都不用解释程序计数器是干什么的吧。可以看成是当前线程所执行代码的字节码行号指示器,注意这个”当前线程“的描述,也就是说,”程序计数器“是”线程私有“的,每个线程都有自己的程序计数器。这个CPU在进行线程切换时就可以快速的返回到一个线程的准确执行位置。

程序计数器是一块比较小的内存区域,虚拟机规范没有为该区域规定任何内存问题,因此,该区域从程序员的角度是比较安全的。


2、JAVA虚拟机栈

就是我们最常听到的”栈“。

这个也是线程私有的,是线程方法执行的内存模型。,每个方法被执行时,都会玩对应线程的栈中添加一栈帧(存放发发执行时的局部变量表、操作栈、动态链接、方法出口等)。

如果线程请求的栈深度大于虚拟机允许的栈深度,抛出StackOverFlowError异常

如果虚拟机栈内存不足以满足一个新的分配栈的请求时,就会抛出内存溢出异常

3、本地方法栈

类似于”虚拟机栈“,不同的是,虚拟机栈为java方法服务,而本地方法栈为虚拟机用得到的native方法服务。

该区域也可能会抛出与”虚拟机栈“相类似的异常


4、方法区

是一块线程共享的内存区域,它用来存放 已经被虚拟机加载的Class的信息、常量、静态变量、即时编译器比那以后的代码等数据

就HotSpot虚拟机将GC分代收集拓展到的方法区,从内存管理的角度,该区域也也被一些程序员被称为永久代(相对于java堆新生代(一个eden区、两个survivor区)、老年代而言的?),而对于其他的虚拟机是不存在永久带的概念的,HotSpot也表示放弃永久代,将方法区迁至NATIVE MEMORY.

当无法满足内存分配的要求是,就会跑出内存溢出异常

方法的一部分:运行时常量池

Class文件中除了类的版本、字段、方法、接口等描述信息外,还有一项是常量池,用来存放编译器生成的各种字面量、符号引用,这部分的信息在类加载后存放到”运行时常量池“。由于虚拟机规范中没有对”运行时常量池“做任何细节上的要求,不同的虚拟机通过不同的方式来实现。一般来说,除了符号引用外,还会将直接引用存储在这里。(直接引用和符号引用参见http://yfxuchao.iteye.com/blog/849908

动态性:运行期间也可能将常量放入池子中,如:String类的intern()方法可以直接将一个字符串放入到池中。

运行时常量池的大小受方法区限制


5、JAVA堆

线程共享的一块最大的内存区域。虚拟机启东时就会创建。虚拟机规范中规定”所有的对象实例和数组“都在此分配。

(随着逃逸分析技术的成熟,对象与数组将不一定在堆上分派。详见http://www.360doc.com/content/10/1111/14/2159920_68483318.shtml)

(注意:java堆虽然是线程共享的,但也存在线程私有的分配缓冲区TLAB(thread local allocation buffer))


6、直接内存

JAVA虚拟机规范中没有规定,但还是要注意的一个区域“

背景:由于java的一种基于通道的缓冲区的io方式,她可以使用native库函数直接分配堆外内存,然后通过java堆里面的一个directByteBuffer对象作为这块内存的引用进行操作,这样的操作可以显著的体改性能,避免了在java堆和native堆中反复的拷贝数据。

既然如此,那么,这块内存区域将会受到本机内存的限制


7、具体的各个区域内存溢出的例子,详见http://blog.csdn.net/chjttony/article/details/7857448,写的很详细。


二、垃圾回收机制与内存分配策略

1、那些对象已死?

a、引用计数法

对于创建的每个对象,记录下指向该对象的引用的数量,当引用数量为0时,表示该对象占用的这块内存可以回收了。有点就是:效率很高,缺点是:无法解决循环引用的问题(如:几个已经无用的对象相互保持引用)。

b、根搜索算法(java采用的方法)

从一系列可以保持对象引用的GC Root出发,向下搜索,搜索走过的所有路径称为“引用链”,引用链不可达的对象将被清除。java中能够作为GC Root的包括以下几种:虚拟机栈中的引用的对象、方法区中类静态属性引用的对象、方法区中常量引用的对象、本地方法战中引用的对象。

注:引用的类型:详见http://www.cnblogs.com/blogoflee/archive/2012/03/22/2411124.html


2、对象的一次自救机会

引用链不可达的对象并不是非死不可。一个对象被清理至少要经过两次标记过程:

当进行一次根搜索算法后,引用链不可达的对象被标记一次。

进行一次标记后,将会判断该对象是否有必要执行finalize ()方法。没必要的情况:没有定义finalize 或 finalize 已被调用过一次。

有必要执行finalize方法的对象被放置到一个队列中去执行finalize方法(不保证方法一定正确执行),然后对该队列中的对象进行第二次标记(当有必要执行finalize时,兑现更可以在finalize中自救:重新与引用链上得任何一个对象建立联系即可,注意:对象只能按这种方式自救一次,因为第二次法没有必要去执行finalize方法了,将被直接清理)。

3、怎样清理:垃圾回收算法

a、标记-清除算法:直接将要清理的对象占用的内存清掉

       主要缺点:效率问题:标记与清除的过程效率都不高

                           空间问题:会产生大量不连续碎片,可能导致之后的大对象内存无法满足

b、复制算法:将使用的内存分为两个部分,一次只用其中的一个部分。在进行垃圾回收时,使用的部分中还有用的内存部分拷贝到保留区域,然后将使用的部分清空

       说明:Hotspot虚拟机将新生代内存分为:一个较大的eden区 8 ,和两个survivor区 1 1,每次使用其中的eden区和其中一个survivor区.

                   当survivor区不够用时,需要依赖老年代进行分配担保

c、标记整理算法。


4、垃圾收集器:

http://blog.csdn.net/java2000_wl/article/details/8030172


5、内存分配语回收策略

a、对象优先在eden区分配

b、大对象直接进入老年代

c、长期存活的对象将进入老年代

d、动态对象年龄判定

e、空间分配担保


三、虚拟机性能监控与故障检测工具

1、jdk命令行工具 ..../jdk7/bin目录里面

2、jdk可视化工具 JCONSOLE、VISUALVM

3、eclipse插件:内存分析工具Memory Analyzer Tool(MAT)


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值