方法区:
(线程共有)
虚拟机加载的类型信息,静态变量、常量、类信息、运行时的常量池
static ,final,Class,常量池
可理解为堆的一部分,永久代和元空间都是方法区的实现,就像类和接口
程序计数器:
一个指针(线程私有)
为了让每个线程正常工作就提出了程序计数器(Programe Counter Register),每个线程都有自己的程序计数器这样当线程执行切换的时候就可以在上次执行的基础上继续执行,仅仅从一条线程线性执行的角度而言,代码是一条一条的往下执行的,这个时候就是程序计数器;JVM就是通过读取程序计数器的值来决定下一条需要执行的字节码指令,进而进行选择语句、循环、异常处理等;
栈:
栈帧(局部变量表,操作数栈,动态链接,方法出口等)
基本数据值、对对象的引用和方法的位置(引用)
new 一个对象就是在栈中添加一个引用,再再堆里面实例一个对象,然后让引用指向那个对象(线程私有)
本地方法栈(线程私有)
堆:
(线程公有)
实例变量,类,方法,常量
新生代:伊甸园区(new出来的对象),幸存区0区,幸存区1区 采用复制算法
老年代:养老区 标记-整理-清除算法
永久区:常驻内存,存放JDK自身携带的class对象。interface元数据,java运行时的环境或类信息,这个区域不存在垃圾回收,关闭虚拟机时释放内存
jdk1.6前:新生代,常量池在方法区
jdk1.7: 永久代逐渐退化,去永久代,常量池在堆中
jdk1.8后:无永久代,常量池在元空间
GC算法
判断对象是不是垃圾:
引用计数法:有对象引用加一,无对象引用减一,为0时回收,较难处理循环引用
可达性分析法:维护了一个对象引用树,在判断垃圾时,从GC根节点开始遍历,如果一个对象不在这个可达性树中,则这个对象为垃圾,
复制算法:伊甸园区和幸存者区大小为8:1:1,也就是新生代中有百分之九十的区域可用,用于新生代,伊甸园区满了进行一次GC,将活着的复制到from区,再次GC时则扫描伊甸园区和from区,将活着的复制到to区,然后将伊甸园区和from区清空,from区和to区互换。复制之后有交换,谁空谁是to区,每次复制将对象年龄加一,当达到JVM参数设置的次数则进入老年代。无内存碎片,但是很浪费空间,有些大的对象复制起来比较耗时。
标记清除算法:标记出存活对象,清除要回收的对象。产生了大量的内存碎片。
标记整理算法:在标记清除的基础上,增加了压缩,将存活对象压缩到一端。无内存碎片但要付出移动对象的成本。
复制算法用于新生代,标记清除和标记整理用于老年代。
内存效率(时间复杂度) :复制算法 > 标记清除 > 标记压缩
内存整齐度 :复制算法 == 标记清除 > 标记压缩 > 标记清除
内存利用率:标记压缩 == 标记清除 > 复制算法
垃圾收集器
Serial收集器#
特点:
出现的最早的,发展最悠久的垃圾收集器。
单线程垃圾收集器。
主要针对新生代内存进行收集
运行机制如下所示
缺点:慢
用处:在客户端上运行还是比较有效。没有线程的开销,所以在客户端还是比较好用的。