JVM的优化

老子叫甜甜 提交于 2019-12-05 12:03:55

jVM组件

类加载器(ClassLoader):加载类

运行时数据区:方法区,虚拟机栈,本地方法栈,堆,程序计数器

执行引擎(面试不聊)翻译成机器语言

本地库接口 :处理其它语言的方法实现

 

内存如何分配:

方法区:存的是类相关的一些信息(类字节码对象,类变量,类方法)堆:存对象实例,区域最大Java虚拟机栈(栈内存):栈帧(封装了方法和变量)->方法入口(main方法)出口本地方法栈:和Java虚拟机栈概念一样,交给本地系统执行程序计数器:记录程序执行的位置,多线程切换时记录,回到记录点继续运行

 

线程共享的区(每个线程都可访问,jvm在而在):方法区,堆线程私有的区(不共享,只有自己线程访问,线程销毁而销毁):java虚拟机栈,本地方法栈,程序计数器​1核多线程:争夺CPU时间片,你执行一行,我抢到了我执行一下​栈内存溢出:StackOverOfFlowError 栈装不下,满了内存溢出OOM:OutOfMemoryError 内存不足    无限创建对象或线程​VM-option(分配栈内存空间大小):     -Xmx20m 堆最大内存大小    -Xms20m 虚拟机启动初始化堆内存大小,最小堆内存    //在堆内存溢出的时候,我们需要排查占用空间比较大的对象    //分析这个对象是否真的需要    //内存溢出    //内存泄漏其它语言实现的方法由native修饰​垃圾回收主战场:堆,也可以开启对方法区的回收

堆(分代)

新生代

三个区(配合GC复制算法):Eden区:对象区(肯定在使用)S1:幸存者1区S2: 幸存者2区两个幸存者区用着一个等待一个​对象在内存种的分配:3个部分    对象头:存储类的指针,锁的标识,年龄    实例数据:数据,字段    对齐填充:自动补齐如8的倍数

年老代

年老代

 

方法区

方法区:又称(永久代,PerSize,元数据空间)​方法区常量池​方法区也有可能会出现内存溢出​动态代理对象存放在方法区

动态代理

jdk实现:    实现1.实现InvercationHandler接口重写方法    实现2.Proxy.newProxyInstance(...)反射调用cglb实现:    new Enhancer().setCallBack(...)

 

 

GC垃圾回收

概念:java中,不需要主动释放对象,由虚拟机自行执行。在JVM中,有一个垃圾回收线程,它是低优先级的,在正常情况下是不会执行的,只有在虚拟机空闲或者当前堆内存不足时,才会触发执行,扫描那些没有被任何引用的对象,并将它们添加到要回收的集合中,进行回收。

那些对象需要被回收?

判断一个对象是否活着?或者GC对象的判定方法?

//1.引用计数法:    给每个对象设置一个引用计数器,每当一个地方引用一次对象计数器就加1,引用失效时减1,当对象的引用计数器为0时就说明这个对象没有被引用的死对象,将被垃圾回收。    缺陷:循环引用会导致对象无法被回收//2.可达性算法:(引用链法)    思想:从一个被称为GC Roots的对象开始往下搜索,如果一个对象的GC Roots没有任何引用链相连时,则说明此对象不可用。    可作为GC Roots的对象有以下几种:        虚拟机栈帧中引用的对象(栈帧本地变量表)        方法区类静态属性引用的对象        方法区常量池引用的对象        本地方法栈JNI引用的对象    //强引用:直接赋值的引用,永远不会被释放,除非手动赋空//弱引用:当内存不够时回收//软引用:GC开始垃圾回收随时可能被回收SoftReference包装    byte[] buff=new byte[1024];    SoftReference<byte[]> b=new SoftReference<>(buff)//强引用转软引用//虚引用:监控对象的状态
垃圾回收方法?
//1.标记-清除:标记出那些要清除的,然后统一回收    缺点:1.效率不高,标记和清除的效率都很低。         2.会产生大量的不连续的内存碎片,空间问题,空间不足时提前触发GC动作//2.复制算法:它把你的内存划分为相等的两部分,一块用完的时候就将还存活的对象复制到第二块内存上,然后一次性清除完第一块内存,再将第二块上的对象复制到第一块。    优点:不会产生内存碎片    缺点:空间浪费,内存代价高,基本上每次都要浪费一半的内存//3.标记-整理:对有用的对象按照一定顺序往前搬,后边没用的对象全部清除,这样就不会产出内存碎片了//4.分代搜集:将堆分为新生代和老年代    新生代:复制算法        对象生存周期短,每次回收都会有大量对象死去,这时采用复制算法    老年代:标记-清除或标记-整理        对象存活率较高,没有额外的空进啊进行分配担保,所以使用标记-整理或者标记清除
垃圾收集器?

根据项目选择合适的垃圾收集器

多种垃圾搜集器:7种,不用记新生代:Serial ParNew ParallelScavenge年老代:​//串行垃圾收集器:全部暂停,等到垃圾清理完,效率更低,更成熟(硬件比较差时,配置比较低时用)    开启串行:-XX:+UseSerialGC//并行垃圾收集器:以吞吐量为主,快速完成,追求吞吐量    开启并行:-XX:UseParallelGC或XX:+UseParallelOldGC//并发清除搜集器:以关注低延迟为目标​//G1搜集器:追求低延迟,并发垃圾搜集器    开启G1:-XX: UseG1GC

类加载机制

//类的加载机制?    虚拟机把描述类的数据从Class文件加载到内存,并对数据进行校验,解析和初始化,最终形成可以被虚拟机直接使用的java类型。​//类加载的生命周期?加载:读class文件验证:符不符合jvm加载要求准备:开辟内存空间解析:把类里面的引用转化为具体的引用初始化:把类里面的所有属性对象初始化使用:卸载://触发类加载的时机?    new关键字    static被调用时    反射调用    初始化一个类时它的父类也会被加载    main方法所处在的类被加载    动态代理触发时被加载//有那些类加载器(四种内置三种)?Class Loader:    Bootstrap class loader//顶层(根)类加载器    ExtenSion class loader//拓展类加载器,jdk里面ext里面的jar包    System class loader//应用程序类加载器,编译成的class文件->classpath    custom class loader //自定义类加载器:通过继承ClassLoader类来实现//类和类加载器的关系?    两个类是否相同和类的加载器是有关系的//双亲委派机制?    答:当一个类收到了类加载请求时,不会自己先去加载这个类,而是将其委派给父类,由父类去加载,如果此时父类不能加载,反馈给子类,由子类去完成类的加载。    类加载器一级一级加载    顶层类加载器->拓展类加载器->应用程序类加载器->有加载没有报错

 

jVM性能监控和故障处理工具

jstat:java堆栈跟踪工具

jps:查看当前运行的java虚拟机和进程号

jstat -gcutil 18904 250 10监控查看

jinfo -flags pid进程号 :查看参数的,更改参数值

jmap -dump:java内存映像工具 内存打印快照*

jhat:虚拟机堆转存储快照分析工具

jstack pid > d:/thread.log:java堆栈跟踪工具*

nid->线程号 查找那个线程比较卡java.lang.state线程的状态 TIME_WATING阻塞,RUNNABLE运行

Linux命令:

//后台运行jar:nohup java -jar *.jar//查看内存情况top -p pid -H

Java可视化监视和管理工具

jconsole.jarvisualVM.jar:多合一故障处理工具

 

JVM调优总结

不断调试的过程。

1:操作系统,32更快,64位更吃内存吞吐量更大,建议用64位2:XMX和XMS设置一样大,MaxPermSize和MinPermSize设置一样大,这样可用减轻伸缩堆大小带来的压力。3.-Xmn年清代的大小    -XX:NewRadio年清代和年老代的比值    Sum建议 年清代和年老代的比例: 3/84.垃圾回收器的选择5.调试的时候设置一些打印参数    -XX:??6.通过jvm监控工具进行监控和调优7.仔细了解自己的应用,如果用了缓存,那么年老代应该大一些

 

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!