一、 java内存区域
1.堆 (线程共享)
2.栈(线程私有)生命周期与线程相同,栈帧(局部变量表,动态链接,方法出口,操作数栈)
3.寄存器(线程私有)
4.方法区(线程共享)类型信息,常量,静态变量
5.常量池(1.8在方法区) 存放编译期生成的字面量和符号引用
6.直接内存 可以使用Native函数库直接分配堆外内存,通过存储在Java堆里面的DirectByteBuffer对象作为这快内存的引用进行操作,避免在java堆和Native堆中来回复制数据
二、查询内存区域的命令
java -XX:PrintCommandLineFlags --version
三、垃圾收集器
并行(parallel)[ˈpærəlel]: 并行描述的是多个垃圾收集器线程之间的关系,说明同一时间有多个线程在协同工作,通常默认用户线程在等待状态
并发(Concurrent): 并发描述的是垃圾收集器线程和用户线程之间的关系,同一时间垃圾收集器线程和用户线程都在运行,由于用户线程并未冻结,所以程序依然能够响应请求,但是由于垃圾收集器占用了一部分资源,此时应用程序的处理的吞吐量将收到一定影响
1、Serial收集器: [ˈsɪəriəl]
- Serial收集器是一个单线程工作的收集器,在进行垃圾回收时,必须暂停其他所有工作线程,直到垃圾回收结束
- 新生代采取复制算法暂停所有用户线程,老年代采取标记-整理算法暂停所有用户线程
- 使用场景:对于内存受限的环境,它是额外内存消耗最小的,对于单核处理器或处理核心数较少的环境来说,Serial收集器没有线程交互的开销,专心做垃圾回收可以获得最高的效率。它依然是HotSpot虚拟机运行在客户端默认新生代收集器,简单高效
2、ParNew收集器(新生代收集器)
- ParNew收集器实质上是Serial收集器的多线程并发版本,使用多个线程进行垃圾回收之外,其他都与Serial一致
- 新生代采取复制算法暂停所有用户线程,老年代采取标记-整理算法暂停所有用户线程
- 目前只有ParNew可以与CMS收集器配合工作,CMS作为老年代的收集器
- ParNew是激活CMS收集器后(命令: -XX:+UseConcMarkSweepGC)的默认新生代收集器
- 默认开启的垃圾收集器线程数和处理器核心数量相同
3、Parallel Scavenge [ ˈskævɪndʒ ] (清除) 收集器(新生代收集器)
- 使用的算法是标记-复制算法
- parallel Sacvenge收集器的特点是它的关注点和其他收集器不同,CMS等收集器关注点事尽可能的缩短垃圾收集是用户线程的停顿时间,parallel Sacvenge 收集器的目标则是达到一个尽可能控制的吞吐量( 吞吐量 = 运行用户代码时间 / ( 运行用户代码时间 + 运行垃圾收集时间 ) )
- Parallel Scavenge收集器提供2个参数用户精确设置吞吐量,分别是控制最大垃圾收集器停顿时间的-XX:MaxGCPauseMillis参数以及设置吞吐量大小的-XX:GCTimeRatio参数
- -XX:MaxGCPauseMillis 是一个大于0的毫秒数,收集器讲尽力保证内存回收花费的时间不超过这个用户设置时间
- -XX:GCTimeRatio 值的大小为 0 < X <100 的整数,默认99
- Parallel Scavenge收集器的还一个参数 -XX:UseAdaptiveSizePolicy,不需要配置新生代大小( -Xmn)、Eden与Survivor区的比例,虚拟机会动态调整这些参数提供最适合的停顿时间或者最大的吞吐量
- 自适应调整策略也是parallel Scavenge收集器区别与其他收集器的一个重要特性
4、Serial Old收集器
- Serial Old收集器是Serial收集器的老年代版本,是一个单线程收集器,使用标记-整理算法,这个收集器的意义也是供客户端模式下的HotSpot虚拟机使用
- 新生代使用复制算法,老年代采用标记-整理算法
- 使用场景 : 作为CMS收集器发生失败时的后备预案,在并发收集Concurrent Mode Failure时使用
5、Parallel Old 收集器 [ˈpærəlel]
- parallel Old 是 Parallel Scavenge的老年代版本,支持多线程并发收集,基于标记-整理算法原因是如果新生代选择了parallel Scavenge收集器,老年代只能选择PS MarkSweep收集器,由于单线程的老年代无法充分利用处理器的并行处理能力,在老年代内存空间比较大而且硬件规格比较高级的运行环境中,这个组合的总吞吐量不一定比ParNew加CMS的组合来的优秀
- 使用场景: 注重吞吐量或者处理器资源比较稀缺的场合,都可以优先考虑Parallel Scavenge和parallel Old收集器
5、CMS收集器 Concurrent Mark Sweep
- cms收集器是一种以获取最短回收停顿时间为目标的收集器
- cms算法采用的是标记-清除算法
- 使用场景: 互联网网站和B/S架构系统
- 垃圾回收过程4个步骤: 1.3步骤会停顿
- 初始标记:仅仅表示GC Root能直接关联到对象
- 并发标记: GC Root 的直接关联对象开始遍历整个对象图的过程,不需要用户线程停顿
- 重新标记:为了修改并发期间,用户线程继续用作而导致标记产生变动的那一部分
- 并发清除:清除掉已经死亡的对象,和用户线程并发运行
- 缺点:1.并发标记阶段占用处理器资源导致应用程序变慢,降低吞吐量2.产生浮动垃圾,在并发标记和并发清除过程中,会产生新的垃圾对象,这次无法回收,只能下次回收3.基于标记-清除算法会产生空间碎片
6、Garbage First收集器(G1)
- 采用标记-整理和标记-复制的算法
- 面向局部收集的设计思路和基于Region的内存布局形式
- G1不再坚持固定大小以及固定数量的分代区域划分,而是把连续的堆分为多个大小相同的独立区域(Region),每一个区域都可以根据需要,扮演新生代的Eden空间、Survivir空间、或者老年代,收集器能够对扮演不同角色的Region采用不同的策略去处理
- Region中还有一类特殊的Humongous [hjuːˈmʌŋɡəs] (极大地),区域,专门用来存储大对象,G1认为大小超过Region一般的对象即可判定认为是大对象,每一个Region的大小可以用 -XX:G1HeapRegionSize设定,取值范围1-32MB,并且是2的N次幂,对于超过整个Region容量的超大对象,将会存储在N个联系的Humongous Region中,G1的大多数行为都把Homongous Region作为老年代的的一部分看待,虽然G1收集器仍然保留新生代和老年代的概念,但是新生代和老年代不在是连续的,它们都是一系列不连续区域的集合
- 优点:避免了整个java堆中进行全区域的垃圾回收,是让G1去跟踪各个Region里面的垃圾堆积的价值大小,然后在后台维护一个优先级列表,每次根据用户设置的收集停顿时间 - XX:MaxGCPauseMillis, 默认200毫秒,优先处理回收收益价值最大的Region,保证了G1收集器在有限的时间内获取尽可能高的收集效率
- 运行过程分为4个步骤
- 初始标记:标记一下GC root可以直接关联到的对象
- 并发标记:遍历初始标记发现GC root对象,时间比较长,可以和用户线程并发执行
- 最终标记:对用户线程做一个短暂的停顿,对并发标记阶段产生的对象进行标记
- 刷选回收:更新Region的统计数据,对个各个Region的回收价值和成本进行排序,根据用户设定的停顿时间来制定回收计划,可以自由选择多个 Region构成回收集,然后把决定回收的Region存活的对象复制到空的Region中,暂停用户线程,由多个收集器并行完成
四、GC root对象
1、虚拟机栈中引用的对象(局部变量、临时变量)
2、方法区中静态属性引用的对象(java类型的应用类型静态变量)
3、方法区中常量引用的对象(字符串常量池)
4、在本地方法栈(Native方法)中引用的对象
5、java虚拟机内部的引用(基本数据类型对应的class对象)
6、所有被同步锁持有的对象
五、volatile关键字
- 可见性:java内存模型是通过在变量修改后将新值同步回主内存,在变量读取前从主内存刷新变量值这个依赖主内存作为传递媒介的方式来实现的
- 禁止指令重排序
六、栈帧
- 局部变量表(方法参数、局部变量)
- 操作数栈
- 动态链接(执行运行时常量池中的引用)
- 方法返回地址
七、创建对象的过程
- 申请内存,赋默认值
- 调用构造方法,将成员变量赋值成初始值
- 建立关联
八、volatile