jvm 随笔 1-概述

2 篇文章 0 订阅

0. 后面慢慢再补充上了吧,目前多是参考的

JVM 内存管理
JIT 即时编译
Java 动态链接
Java 字节码校验
JVM 常见参数

JVM处理流程:
请添加图片描述

类加载器

详见随笔

字节码校验

校验器负责检查那些无法执行的明显有破坏性的操作。除了系统类之外,其他类都要被校验。
检查啥?
	变量要在使用之前进行初始化
	方法调用与对象引用类型之前要匹配
	访问私有数据和方法的规则没有被违背
	对本地变量的访问落在运行时堆栈内
	运行时堆栈没有溢出

JIT 即时编译

java编译
	动态编译dynamic compilation)
		(指的是“在运行时进行编译”;与之相对的是事前编译(ahead-of-time compilation,简称AOT),也叫静态编译(static compilation)
	JIT编译(just-in-time compilation)	
		狭义来说是当某段代码即将第一次被执行时进行编译,因而叫“即时编译”。JIT编译是动态编译的一种特例。
	自适应动态编译(adaptive dynamic compilation)
		它通常执行的时机比JIT编译迟,先让程序“以某种式”先运行起来,收集一些信息之后再做动态编译。这样的编译可以更加优化。
				

动态链接

当编译一个Java程序的时候,会得到程序中每个类或者接口的独立的class文件,当程序运行的时候,JVM转载程序的类和接口,在动态连接的过程中把它们互相勾连起来。
常量池:每一个被JVM装载的类或接口都有一份内部版本的常量池
运行时常量池:常量池中的符号引用被解析后放入运行时常量池
当一个类型被首次装载时,所有来自该类型的符号引用都装载到了类型的运行时常量池。
而经过解析(resolve)之后,也就是把符号引用替换为直接引用,解析的过程会去查询全局字符串池,也就是StringTable,以保证运行时常量池所引用的字符串与全局字符串池中所引用的是一致的。

jvm 内存组成

请添加图片描述

计算机PC寄存器是下一条指令地址,JVM程序计数器是当前指令的地址

jvm堆
	可以位于物理上不连续的空间,但是逻辑上要连续
	Java堆又称为CG堆,分为新生区和老年区,新生区又分为Eden区、From Survivor区和To Survivor

jvm方法区
	又称为Non-Heap,非堆,与Java堆区分开来
	仅限于HotSpot虚拟机
	存储一个类型所使用到的所有类型,域和方法的符号引用

常量池
	1.6 方法区
	1.7 堆
	1.8 独立到元空间(meta space)
	
JVM内存	
	JVM内存划分为堆内存和非堆内存
		堆内存(GC堆)
			年轻代(Young Generation)
				Eden
				Survivor0/1
				官方推荐新生代占堆的的3/8,Survivor占新生代的1/10。	
			老年代(Old Generation)
		非堆内存
			永久代(Permanent Generation)

请添加图片描述

JVM自动内存管理=分配内存+回收内存

jvm 实现

HotSpot VM
	Sun JDK和OpenJDK中所带的虚拟机,也是目前使用范围最广的Java虚拟机。
	特点
		通过甄别出引用频率较高的代码,通知JIT编译器方法为单位进行编译
		引用较多的方法,触发标准编译和OSR(栈上替换)编译动作
		无须等待本地代码完成编译再执行程序,其编译器、解释器协同工作,平衡程序的启动时间与代码解析效率
	具体实现
		HotSpot Client VM 主要优化启动时间、内存占用
		HotSpot Server VM 通过优化堆大小、垃圾回收器、编译器以获得持久的运行稳定性

垃圾回收算法

标记清除
	标记、清除本身的效率不高
	清理回收之后,造成内存碎片较多,不连续
复制
	Serial收集器、ParNew收集器、Parallel scavenge收集器
	很好的解决垃圾收集的内存碎片问题
	就是要牺牲一半的内存
	优化策略
		年轻代中增设survivor用于复制,并且分别仅占用1/10
		溢出survivor内存空间的对象将转移至老年代
标记整理
	标记、清理需要回收的对象
	将存活对象向一侧移动,清理内存碎片
分代收集
	不同代采用不同的算法

垃圾回收器

使用的是jdk8,所以默认使用ParallelGC收集器,也就是在新生代使用Parallel Scavenge收集器,老年代使用ParallelOld收集器

特点:
	Serial/serial old:单线程(stop the world,gc时停止其他线程)、复制/标整、较为简单
		ParNew:多线程, 复制(相当于多线程的serial)
	Parallel scavenge/Parallel old:多线程,高效利用cpu,尽快完成计算任务,吞吐量大
	cms(Concurrent Mark Sweep):老年,多线程,标清,响应快(停顿很短),适合做交互
	G1:新+老,多线程,(整体上标整,局部使用复制)
	
常用组合:
	Serial + serial old 新生代和老年代都是单线程,简单
	ParNew+ serial old 新生代多线程,老年代单线程,简单
	Parallel scavenge + Parallel old 该组合完成吞吐量优先虚拟机,适用于后台计算
	cms收集器 完成响应时间短虚拟机,适用于用户交互
	G1收集器 面向服务端的垃圾回收器

可选的组合:
在这里插入图片描述

遇到的问题

StackOverflowError栈溢出
	发生在:程序计数器、jvm栈、本地方法栈(这些刚好也是线程私有的)
	线程请求的栈深度大于虚拟机所允许的深度。 报错信息:java.lang.StackOverflowError
	解决方法:
		检查代码是否有无限循环即可。
	
OutOfMemoryError内存泄露
	java.lang.OutOfMemoryError:unable to create new native thread
		栈动态扩展也无法申请到所需要内存
		解决方法:这个异常问题本质原因是我们创建了太多的线程,而能创建的线程数是有限制的,导致了异常的发生
			如果程序中有bug,导致创建大量不需要的线程或者线程没有及时回收,那么必须解决这个bug,修改参数是不能解决问题的。
			如果程序确实需要大量的线程,现有的设置不能达到要求,那么可以通过修改MaxProcessMemory,JVMMemory,ThreadStackSize这三个因素,来增加能创建的线程数:MaxProcessMemory 表示使用64位操作系统,JVMMemory 表示减少 JVMMemory 的分配,ThreadStackSize 表示减小单个线程的栈大小。
		(MaxProcessMemory - JVMMemory - ReservedOsMemory) / (ThreadStackSize) = Number of threads
		 当你创建一个线程的时候,虚拟机会在JVM内存创建一个Thread对象同时创建一个操作系统线程,而这个系统线程的内存用的不是JVMMemory,而是系统中剩下的内存(MaxProcessMemory - JVMMemory - ReservedOsMemory)。由公式得出结论:你给JVM内存越多,那么你能创建的线程越少,越容易发生 java.lang.OutOfMemoryError: unable to create new native thread
	java.lang.OutOfMemoryError: Java heap space
		堆中内存不足以分配,并且无法继续扩展
		解决方法:根本原因在于对象实例太多,Java堆溢出,则解决方法有两个种,要么增大堆内存,要么减少对象示例
			从增大堆内存方面入手:增加Java虚拟机中Xms(初始堆大小)和Xmx(最大堆大小)参数的大小。如:set JAVA_OPTS= -Xms256m -Xmx1024m
			一般来说,正常程序的对象,堆内存时绝对够用的,出现堆内存溢出一般是死循环中创建大量对象,检查程序,看是否有死循环或不必要地重复创建大量对象。找到原因后,修改程序和算法。
	java.lang.OutOfMemoryError: PermGen space
		同理,方法区无法分配到足够的内存
		解决方法:要么增大方法区,要么减少jar、class文件
			(增大方法区内存空间)增加java虚拟机中的XX:PermSize和XX:MaxPermSize参数的大小,其中XX:PermSize是初始永久保存区域大小,XX:MaxPermSize是最大永久保存区域大小。如web应用中,针对tomcat应用服务器,在catalina.sh 或catalina.bat文件中一系列环境变量名说明结束处增加一行:
			从减少jar、class文件入手:清理应用程序中web-inf/lib下的jar,如果tomcat部署了多个应用,很多应用都使用了相同的jar,可以将共同的jar移到tomcat共同的lib下,减少类的重复加载。

为什么-xmx(最大)、-xms(初始分配)设定一样?
	(等同于设置堆内存为不可扩展和收缩)
	避免JVM在运行过程中、每次垃圾回收完成后向OS申请内存:因为所有的可以分配的最大内存第一个就给它(JVM)了。
	延后启动后首次GC的发生时机、减少启动初期的GC次数:因为第一次给它分配了最大的;
	尽可能避免使用linux的swap space:swap space为交换空间

java支持运行时输出jvm实时内存分配情况
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值