几种主要的jvm 参数
JVM的参数形式:
- -X 开头的参数都是非标准的参数(不是所有的JVM都实现了)
- -XX 都是不稳定的并且不推荐在生产环境中使用
* 布尔类型的参数 格式 -XX:+<option> 打开/-XX:-<option> 关闭 例如: -XX:PrintGCDetails 打开GC信息(调优和定位内存回收问题经常使用) * 数字型参数 格式 -XX:<option>=<number> 例如 -XX:NewRatio=2 * 字符型参数 格式 -XX:<option>=<string> 例如 -XX:HeapDumpPath=./java_pid.hprof
-client :设置JVM使用client模式,特点启动较快(神机不明显(I5/8G/SSD))
开发人员会用到的标准参数
-server :设置JVM使用server模式。64位JDK默认启动该模式
-agentlib:libname[=options] :用于加载本地的lib
-agentlib:hprof :用于获取JVM的运行情况
-agentpath:pathnamep[=options] :加载制定路径的本地库
-Dproperty=value :设置系统属性名/值对
-jar :制定以jar包的形式执行一个应用程序
-javaagent:jarpath[=options] :实现premain方法在main方法前执行可以利用该方式玩一个JVM层面的hook很有意思的东西
-verbose:jni :输出native方法的调用情况玩JNI必备技能
Java堆栈大小相关
Xms :设置Java堆栈的初始化大小
-Xmx :设置最大的java堆大小
-Xmn :设置Young区大小
-Xss :设置java线程堆栈大小
-XX:PermSize and MaxPermSize :设置持久带的大小
-XX:NewRatio :设置年轻代和老年代的比值
-XX:NewSize :设置年轻代的大小
-XX:SurvivorRation=n :设置年轻代中E去与俩个S去的比值
垃圾回收器信息和设置垃圾回收器(串行、并行、并发等行为的收集器)
-verbose:gc :记录GC运行以及运行时间,一般用来查看GC是否有瓶颈
-XX:+PrintGCDetails :记录GC运行时的详细数据信息,包括新生占用的内存大小及消耗时间
-XX:-PrintGCTimeStamps :打印收集的时间戳
-XX:+UseParallelGC :使用并行垃圾收集器
-XX:-UseConcMarkSweepGC :使用并发标志扫描收集器
-XX:-UseSerialGC :使用串行垃圾收集器
-Xloggc:filename :设置GC记录的文件
-XX:+UseGCLogFileRotation :启用GC日志文件的自动转储
-XX:GCLogFileSize=1M :控制GC日志文件的大小
类加载和跟踪类加载和卸载的信息
Xbootclasspath :指定需要加载,但不想通过校验类路径。
JVM会对所有的类在加载前进行校验并为每个类通过一个int数值来应用
-XX:+TraceClassLoading :跟踪类加载的信息(诊断内存泄露很有用)
-XX:+TraceClassUnloading :跟踪类卸载的信息(诊断内存泄露很有用)
JVM如何加载字节码文件
从被加载到虚拟机内存到卸载出内存的生命周期包括:加载->连接(验证->准备->解析)->初始化->使用->卸载
初始化的5种情况:
1.使用new关键字实例化对象时,读取或设置一个类的静态字段,除被final修饰经编译结果放在常量池的静态字段,调用类的静态方法时。 2.使用java.lang.reflect包方法对类进行反射调用时。(Class.forName())。 3.初始化子类时,如果父类没有初始化。 4.虚拟机启动时main方法所在的类。 5.当使用JDK1.7动态语言支持时,java.lang.invoke.MethodHandle实例解析结果为REF_getStatic,REF_putStatic,REF_invokeStatic的方法句柄,且对应类没有进行初始化。
加载 加载是类加载的第一个阶段,虚拟机要完成以下三个过程:
1.通过类的全限定名获取定义此类的二进制字节流。 2.将字节流的存储结构转化为方法区的运行时结构。 3.在内存中生成一个代表该类的Class对象,作为方法区各种数据的访问入口。
验证 目的是确保class文件字节流信息符合虚拟机的要求。
准备 为static修饰的变量赋初值,例如int型默认为0,boolean默认为false。
解析 虚拟机将常量池内的符号引用替换成直接引用。
初始化 初始化是类加载的最后一个阶段,将执行类构造器< init>()方法,注意这里的方法不是构造方法。该方法将会显式调用父类构造器,接下来按照java语句顺序为类变量和静态语句块赋值。
方法调用
Java是一门面向对象的语言,它具有多态性。那么虚拟机又是如何知道运行时该调用哪一个方法?
静态分派是在编译期就决定了该调用哪一个方法而不是由虚拟机来确定,方法重载就是典型的静态分派。 动态分派是在虚拟机运行阶段才能决定调用哪一个方法,方法重写就是典型的动态分派。
动态分派的实现:当调用一个对象的方法时,会将该对象的引用压栈到操作数栈,然后字节码指令invokevirtual会去寻找该引用实际类型。如果在实际类型中找对应的方法,且访问权限足够,则直接返回该方法引用,否则会依照继承关系对父类进行查找。实际上,如果子类没有重写父类方法,则子类方法的引用会直接指向父类方法
由Java虚拟机自带的类加载器所加载的类,在虚拟机的生命周期中,始终不会被卸载。
Java虚拟机自带的类加载器包括根类加载器、扩展类加载器和系统类加载器。Jvm会始终引用这些类加载器,而这些类加载器则会始终引用它们所加载的类的Class对象如果程序运行过程中,将引用变量都置为null,此时对象结束生命周期,代表Sample类的Class对象也结束生命周期,Sample类在方法区内的二进制数据被卸载。当再次有需要时,会检查Sample类的Class对象是否存在,如果存在会直接使用,不再重新加载;如果不存在Sample类会被重新加载,在Java虚拟机的堆区会生成一个新的代表Sample类的Class实例(可以通过哈希码查看是否是同一个实例)。
简述重排序,内存屏障,happen-before,主内存,工作内存
在执行程序时为了提高性能,编译器和处理器常常会对指令做重排序
重排序有三种类型:
1.编译器优化的重排序.java -----> .class
编译器在不改变单线程程序语义的前提下,可以重新安排语句的执行顺序
2.指令级并行的重排序.class----->汇编
现代处理器采用了指令级并行技术来将多条指令重叠执行。
如果不存在数据依赖性,处理器可以改变语句对应机器指令的执行顺序
3.内存系统的重排序汇编 ---->CPU指令执行
由于处理器使用缓存和读/写缓冲区,这使得加载和存储操作看上去可能是在乱序执行
重排序只对于那些在当前线程没有依赖关系的有效,有依赖关系的是不会重排序的。
java重排序的最低保证是,as if serial,即在单个线程内,看起来总认为代码是在顺序运行的,但是从别的线程来看,这些代码运行的顺序就不好说了。
为了保证内存可见性,java编译器再生成指定序列的适当位置会插入内存屏障指令来禁止特定类型的处理器重排序,内存屏障指令分为四个类型。
Java内存模型分为主内存(线程共享),和工作内存(线程独享)。
软引用(SoftReferenc)、弱引用(WeakReference)和虚引用
2、强引用
强引用就是指在程序代码之中普遍存在的,类似“Object obj = new Object()”这类的引用,只要强引用还存在,垃圾收集器永远不会回收掉被引用的对象。
3、软引用(SoftReference)
软引用用来描述一些还有用,但并非必需的对象。对于软引用关联着的对象,在系统将要发生内存溢出异常之前,将会把这些对象列进回收范围之中并进行第二次回收。如果这次回收还是没有足够的内存,才会抛出内存溢出异常。在JDK 1.2之后,提供了SoftReference类来实现软引用。
4、弱引用(WeakReference)
弱引用也是用来描述非必需对象的,但是它的强度比软引用更弱一些,被弱引用关联的对象只能生存到下一次垃圾收集发生之前。当垃圾收集器工作时,无论当前内存是否足够,都会回收掉只被弱引用关联的对象。在JDK 1.2之后,提供了WeakReference类来实现弱引用。
5、虚引用(PhantomReference)
虚引用也称为幽灵引用或者幻影引用,它是最弱的一种引用关系。一个对象是否有虚引用的存在,完全不会对其生存时间构成影响,也无法通过虚引用来取得一个对象实例。为一个对象设置虚引用关联的唯一目的就是希望能在这个对象被收集器回收时收到一个系统通知。在JDK 1.2之后,提供了PhantomReference类来实现虚引用。
堆为什么要分e区和两个s区
1.4.2分代收集算法
判断一个对象是否可以回收,是否可以手动回收,不可以这个方法还有什么作用
可达性分析法,System.gc()函数。gc()函数的作用只是提醒虚拟机(full gc):程序员希望进行一次垃圾回收。但是它不能保证垃圾回收一定会进行,而且具体什么时候进行是取决于具体的虚拟机的,不同的虚拟机有不同的对策。也是调用 Runtime.getRuntime().gc();
内存映射缓存区是什么
什么情况下会发生栈内存溢出
Java 程序来判断 JVM 是 32 位 还是 64 位
内存分配与回收策略
垃圾回收器可以马上回收内存吗?有什么办法主动通知虚拟机进行垃圾回收?
串行(serial)收集器和吞吐量(throughput)收集器的区别是什么
举个实际的场景,选择一个GC策略
标记清除、标记整理、复制算法的原理与特点?分别用在什么地方
如果让你优化收集方法,有什么思路
JAVA内存泄漏原因和检测工具
旧生代的对象都是新生代复制过来的吗
不一定,当新生代已满,对于将要进入新生代的对象会暂存在旧生代。