JVM内存模型
环卫工人(垃圾回收器)
如下是C语言释放内存空间的话比较复杂,容易出错,没有java开发有效率
如何发现垃圾?
原始方法:引用计数法
--一个对象被赋值给一个变量时,引用计数+1;
--持有引用的变量退出作用域时,引用计数-1.
但是如下比如说两个对象引用(obj1,obj2)分别引用了实例1,实例2,实例1里面的属性又引用了实例2,实例2里面的属性又引用了实例1这个时候引用计数法的缺陷就表现出来了,比如代码里的作用域都结束了但两个实例对象还在相互引用(这时这两个对象应该已经是垃圾了,但是还存在相互关系就判断不出来它是垃圾,不回收)
根搜索算法(GC Root)
--栈帧里的局部变量所引用的对象;
--方法区的静态变量和常量所引用的对象;
如下图6个对象:
对象1的根在方法区不算垃圾
对象2的根在某个栈帧里不算垃圾
对象4的根在方法栈里不算垃圾
对象6没有直接的根,但被非垃圾的对象4引用了所以它也不是垃圾
对象3被对象5引用了但对象5没有根所以都是垃圾.
垃圾回收也要与时俱进
标记清除法
黑色的是垃圾对象,绿色空白内存,灰色的非垃圾对象
比较直接是垃圾对象就腾出来
缺点:很多碎片,没有连在一起,哪天我们要保存几G的文件就悲剧了,看起来空闲空间挺大,放一个完整文件又放不进去.
分段复制算法
用一半留一半,用起来效率比较高
需要清理时,把需要存留的对象copy到下面那一半,然后把上面全清空
标记整理算法
算法比较复杂,但比较灵活,效率也比较高
尽量不往两头放,分配对象尽量往上面放,紧挨着
每次回收就先整理一下,空白的一边,用过的一边,把不怎么用的放前面
不想分段算法那样严格,因为有时候可能已经用了一半多了.
分代收集算法
伊甸园:西方故事里人刚出生的地方(刚new出来的对象就放着里面)
生存区:又分From、To(分段法制法)
From :例如对象经历了5次回收还没被回收掉就证明它的生命周期应该比较长就把它放到From里来
老年代:回收15次后还存在就有很大几率会一直使用移到老年代里来
如何编写高效,健壮的Java程序
①:尽量不要在循环中使用try...catch、new对象
②:把频繁使用的短命对象缓存起来
③:尽可能使用栈内变量(方法内局部变量)
④:不要用异常来控制代码流程
⑤:用线程池、连接池,不要自己创建
⑥:学会读Java核心API源代码
⑦:推荐一本java进阶的书《Effecitve Java》
内存泄漏与内存溢出
实例1
实例2