1.在java中,他的内存管理分为两个方面.内存分配(创建java对象的时候)和内存回收,这两个方面都是有JVM自动完成的.
java垃圾回收机制GC(Garbage Collection)
两件事:1 内存回收 2.碎片管理
2需要注意3点:
(1)垃圾回收并不会按照程序员的要求,随时惊喜GC
(2)垃圾回收机制并不会及时的清理内存,尽管有时候程序需要额外的内存
(3)程序员不能对垃圾回收进行控制
ps:
GC:能清除在堆上分配的内存(纯java语言的所有对象都在堆上使用new分配内存),而不能清除栈上分配的内存
finalize():对栈上的对象进行内存回收
java提供finalize()方法,垃圾回收器准备释放内存的时候,会先调用finalize()。
(1).对象不一定会被回收。
(2).垃圾回收不是析构函数。
(3).垃圾回收只与内存有关。
(4).垃圾回收和finalize()都是靠不住的,只要JVM还没有快到耗尽内存的地步,它是不会浪费时间进行垃圾回收的。
3垃圾回收算法
1)串行回收(只用一个CPU)和并行回收(多个CPU才有用):串行回收是不管系统有多少个CPU,始终只用一个CPU来执行垃圾回收操作,而并行回收就是把整个回收工作拆分成多个部分,每个部分由一个CPU负责,从而让多个CPU并行回收。并行回收的执行效率很高,但复杂度增加,另外也有一些副作用,如内存碎片增加。
2)并发执行和应用程序停止 :应用程序停止(Stop-the-world)顾名思义,其垃圾回收方式在执行垃圾回收的同时会导致应用程序的暂停。并发执行的垃圾回收虽然不会导致应用程序的暂停,但由于并发执行垃圾需要解决和应用程序的执行冲突(应用程序可能在垃圾回收的过程修改对象),因此并发执行垃圾回收的系统开销比Stop-the-world高,而且执行时需要更多的堆内存。
3)
1.CMS (Concurrent Mark Sweep)收集器,常见的B/S架构的应用就适合用这种收集器,因为其高并发,高响应的特点.
CMS收集器是基于“标记-清除”算法实现的,整个收集过程大致分为4个步骤:
初始标记(CMS initial mark)、并发标记(CMS concurrenr mark)、重新标记(CMS remark)、并发清除(CMS concurrent sweep)。
初识标记和重新标记会暂停其他线程.但是处理速度很快.整体来说.CMS收集器的内存回收过程是与用户线程一起并发执行的.
CMS收集器的优点:并发收集、低停顿,但是CMS还远远达不到完美。
CMS收集器主要有三个显著缺点:
1.对CPU资源非常敏感
2.无法处理浮动垃圾
3.使用 "标记-清除"后,会产生大力量碎片
2.G1收集器。相比CMS收集器有不少改进,首先基于标记-整理算法,不会产生内存碎片问题,其次,可以比较精确的控制停顿
3.Serial Old。Serial Old是Serial收集器的老年代版本,它同样使用一个单线程执行收集,使用“标记-整理”算法。主要使用在Client模式下的虚拟机。
4.Parallel Old。Parallel Old是Parallel Scavenge收集器的老年代版本,使用多线程和“标记-整理”算法。
5.RTSJ垃圾收集器,用于Java实时编程
常用垃圾收集算法
① 清除-压缩
支持压缩的垃圾回收器(标记-压缩 = 标记清除+压缩)会把所有的可达对象搬迁到一端,然后直接清理掉端边界以外的内存,减少了内存碎片。
image.png
②标记-清除算法
不压缩的垃圾回收器(标记-清除)要遍历两次,第一次先从跟开始访问所有可达对象,并将他们标记为可达状态,第二次便利整个内存区域,对未标记可达状态的对象进行回收处理。这种回收方式不压缩,不需要额外内存,但要两次遍历,会产生碎片
image.png
③复制式的垃圾回收器:将堆内存分成两个相同空间,从根(类似于前面的有向图起始顶点)开始访问每一个关联的可达对象,将空间A的全部可达对象复制到空间B,然后一次性回收空间A。对于该算法而言,因为只需访问所有的可达对象,将所有的可达对象复制走之后就直接回收整个空间,完全不用理会不可达对象,所以遍历空间的成本较小,但需要巨大的复制成本和较多的内存。
image.png
4.java分代收集算法
Java主要采用了分代收集算法。分代收集算法主要将对象存活期的长短将内存进行划分。
Java主要将内存划分为两部分:新生代和老生代
Java的新生代中,对象的存活率低,存活期期会相对会比较短一些,所以可以选用复制算法来进行内存回收。
Java的老生代中,对象的存活率比较高,并且相对存活期比较长一些,可以采用标记-清除-压缩的算法来进行内存回收。
5.内存管理小技巧
1)尽量使用直接量,eg:String javaStr = “小学徒的成长历程”;
2)使用StringBuilder和StringBuffer进行字符串连接等操作;
3)尽早释放无用对象;
4)尽量少使用静态变量;
5)缓存常用的对象:可以使用开源的开源缓存实现,eg:OSCache,Ehcache;
6)尽量不使用finalize()方法;
7)在必要的时候可以考虑使用软引用SoftReference。
网友评论