构造性能的度量,原则与方法
1.内存管理模式:堆 栈
操作系统的内存映射已经在深入理解计算机系统这门课中学习过了。
内存对象模型
每个对象存储在内存的一段连续空间之中。
对象在堆中分配内存,对象引用指向对象指向对象在堆中的起始地址,非基本数据类型的变量等价于对象引用。一个引用指向一个其他对象,一个对象可以被多个引用指向。
对象管理的模式
三种:静态,基于堆,基于栈
静态内存分配:在编译阶段就已经确定分配的内存
基于栈的和基于堆的都是动态内存分配:运行时分配内存,建立新的内存对象。
static mode
将程序load进内存的时候或开始执行的时候,确定所有对象的分配,不支持递归,不支持动态创建可边长的复杂数据类型。
stack-based mode
栈存储方法调用及方法执行过程中的内部数据,新进后出,无法支持复杂的数据类型。
heap-based mode
堆:将内存分为多个小块,每块包含一个对象或者未被占用。自由的内存管理模式,可管理复杂的动态数据结构。
Java内存管理模型
主要问题:如何在堆上创建新对象,当对象不再有引用指向时,如何删除对象,释放内存
(1)Stack:
每个线程之间都有自己的栈,各线程之间彼此不可见,多线程之间传递数据,是通过复制而非引用
所有的基本数据类型都在栈上创建
(2)Heap:
所有的对象都在堆上创建,局部变量的对象也是在堆上创建。
堆上创建的对象可以被所有线程共享引用,如果两个线程同时调用同一个对象的某个方法,他们分别保留这个方法的局部拷贝。
GC
三种模式下的内存回收:
(1)static:无需内存回收,所有的都是已经确定的
(2)stack:按照block整体进行
(3)heap:较复杂
内存回收:
(1)对象的活性:
对象之间的引用关系构成了有向图,从root可以到达的对象成为活对象,不可达的对象为死对象
(2)垃圾回收
垃圾回收器根据对象活性判断是否需要回收,死对象需要被回收。
非自动垃圾回收
全靠程序员手动回收垃圾,主要有一下方法
1.防御式编程:复制对象而非引用,在局部回收内存
2.配对原则:有new操作就有对应的delete()操作
GC的四种基本算法
引用计数
为每个object存储一个计数RC,当有其他reference指向它时, RC++;当其他reference与其断开时, RC--;如果RC==0,则回收它。
引用计数方法的优点:简单、计算代价分散,“幽灵时间”短->0
引用计数方法的缺点:不全面(容易漏掉循环引用的对象)、并发支持较弱、占用额外内存空间、等
标记清除
为每个object设定状态位(live/dead)并记录,即mark阶段;将标记为dead的对象进行清理,即sweep可阶段。
优点:可理解性,低耦合性,不需要移动对象
缺点:耗时较长,每次都需要遍历
标记整理
标记对象(如Mark-Sweep)。- 将任何带有标记的东西移到garage的后面。
- 毁掉garage前面的所有东西
优缺点和mark-sweep相同
复制
碎片对显式内存管理器也是一个问题
该GC策略与mark-compact的区别在于:不是在同一个区域内进行整理,而是将live对象全部复制到另一个区域
JVM的垃圾回收
Java GC将堆分为不同的区域,各区域采用不同的GC策略,以提高GC的效率。
针对年轻代: 只有一小部分对象可较长时间存活,故采用copy算法减少GC代价
针对年老代:这里的对象有很高的幸存度,使用Mark-Sweep或Mark-Compact算法
只有当某个区域不能再为对象分配内存时(满),才启动GC
每个区域的策略
(1)针对younggeneration, 使用minor GC进行垃圾收集,Minor GC所需时间较短 ,如果历经多次minor GC仍存活下来,将其copy到old generation。
(2) 如果old generation满了,则启动full GC,Old generation满,意味着无法进行下一次minor GC了 。Minor GC和full GC独立进行,减小代价。
(3)当perm generation满了之后,无法存储更多的元数据,也启动full GC
各区域参数设置
通过以下参数设置younggeneration的尺寸
–Xms 堆的最小值
–Xmx 堆的最大值
-XX: NewSize=<n>[g|m|k] 年轻代的最小值
-XX: MaxNewSize=<n>[g|m|k]年轻代的
-Xmn<n>[g|m|k]
-XX:NewRatio=<n>新:旧
-XX:SurvivorRatio=<n> eden: