计算机语言之java底层篇一
JVM
问:什么是java虚拟机?为什么java被称作是平台无关的编程语言?
答:Java虚拟机是一个可以执行Java字节码的虚拟机进程。Java源文件被编译成能被Java虚拟机执行的字节码文件。
Java被设计成允许应用程序可以运行在任意的平台,而不需要程序员为每一个平台单独重写或者是重新编译。Java虚拟机让这个变为可能,因为它知道底层硬件平台的指令长度和其他特性。
JVM 内存结构
问:堆、栈、方法区、直接内存、运行时常量池?
答:所有的对象实例和数组都要在堆上分配;堆的主要作用就是用来分配给对象生存的空间。方法区是各个线程共享的内存区域,用于存储被虚拟机加载的类信息,常量,静态常量,即时编译器编译后的代码,运行时常量池。在HotSpot上也被称为“永久代”。这一区域主要的知识点是类加载的过程,这一过程分为五个阶段,分别是加载,验证,准备,解析,初始化。虚拟机栈是描述java方法执行的内在模型。
栈帧是用于支持虚拟机进行方法调用和方法执行的数据结构,它是虚拟机运行时数据区中的虚拟机栈的栈元素,栈帧包括:局部变量表,操作数栈,动态链接(每个栈帧都包含一个指向运行时常量池中该栈帧所属方法的引用),方法出口方法区等。
运行时常量池(Runtime Constant Pool),它是方法区的一部分。Class文件中除了有类的版本、字段、方法、接口等描述等信息外,还有一项信息是常量池(Constant Pool Table),用于存放编译期生成的各种字面量和符号引用,这部分内容将在类加载后存放到方法区的运行时常量池中。直接内存(Direct Memory),直接内存(Direct Memory)并不是虚拟机运行时数据区的一部分,也不是Java虚拟机规范中定义的内存区域,但是这部分内存也被频繁地使用,而且也可能导致OutOfMemoryError异常出现。本地方法栈与虚拟机栈作用相似,后者为虚拟机执行Java方法服务,而前者为虚拟机用到的Native方法服务。与PC寄存器一样,Java虚拟机栈也是线程私有的。每一个JVM线程都有自己的java虚拟机栈,这个栈与线程同时创建,它的生命周期与线程相同。
静态分派(重载)
动态分派(重写)
Java 内存模型
问:计算机内存模型、缓存一致性、MESI 协议?
答:
可见性、原子性、顺序性、happens-before、
内存屏障、synchronized、volatile、final、锁
垃圾回收
问:GC 算法:标记清除、标记整理、引用计数、复制、标记压缩、分代回收、增量式回收?
答:回收机制分为分代复制垃圾回收和标记垃圾回收,增量垃圾回收,垃圾回收机制,垃圾收集是将分配对象但不在使用内存回收或释放对象的过程。如果一个对象没有指向他的应用或者其复制为null,则此对象适合进行垃圾回收,
分代回收,把不同生命周期的对象放在不同代上,不同代上采用最适合它的垃圾回收方式进行回收。虚拟机中的共划分为三个代:年轻代(Young Generation)、年老点(Old Generation)和持久代(Permanent Generation)。由于对象进行了分代处理,因此垃圾回收区域、时间也不一样。GC有两种类型:Scavenge GC和Full GC。
标记清除算法由两个阶段组成:
① 标记阶段,标记所有的可访问对象。
② 收集阶段,垃圾收集算法扫描堆并回收所有的未标记对象。
增量垃圾回收,它的存在是为了解决标记清除的长停顿问题,这种GC算法也要写屏障,来记录引用关系的变化。虽然这种方式控制了中断最高时间,但是由于中断次数增加,GC总时间是增加的。
可以有效避免内存泄漏。
内存泄漏与内存溢出:内存泄漏,不能将内存充分利用,ZGC是未来的趋势。
问:JVM的永久代中会发生垃圾回收么?
答:垃圾回收不会发生在永久代,如果永久代满了或者是超过了临界值,会触发完全垃圾回收(Full GC)。如果你仔细查看垃圾收集器的输出信息,就会发现永久代也是被回收的。这就是为什么正确的永久代大小对避免Full GC是非常重要的原因。
JVM 参数及调优
问:-Xmx、-Xmn、-Xms、Xss、-XX:SurvivorRatio、
-XX:PermSize、-XX:MaxPermSize、-XX:MaxTenuringThreshold?
答:java -Xmx3550m -Xms3550m -Xmn2g -Xss128k
-Xmx3550m:设置JVM最大可用内存为3550M.
-Xms3550m:设置JVM促使内存为3550m.此值可以设置与-Xmx相同,以避免每次垃圾回收完成后JVM重新分配内存.
-Xmn2g:设置年轻代大小为2G.整个堆大小=年轻代大小 + 年老代大小 + 持久代大小.持久代一般固定大小为64m,所以增大年轻代后,将会减小年老代大小.此值对系统性能影响较大,Sun官方推荐配置为整个堆的3/8.
-Xss128k:设置每个线程的堆栈大小.JDK5.0以后每个线程堆栈大小为1M,以前每个线程堆栈大小为256K.更具应用的线程所需内存大小进行 调整.在相同物理内存下,减小这个值能生成更多的线程.但是操作系统对一个进程内的线程数还是有限制的,不能无限生成,经验值在3000~5000左右.
java -Xmx3550m -Xms3550m -Xss128k -XX:NewRatio=4 -XX:SurvivorRatio=4 -XX:MaxPermSize=16m -XX:MaxTenuringThreshold=0
-XX:NewRatio=4:设置年轻代(包括Eden和两个Survivor区)与年老代的比值(除去持久代).设置为4,则年轻代与年老代所占比值为1:4,年轻代占整个堆栈的1/5
-XX:SurvivorRatio=4:设置年轻代中Eden区与Survivor区的大小比值.设置为4,则两个Survivor区与一个Eden区的比值为2:4,一个Survivor区占整个年轻代的1/6
-XX:MaxPermSize=16m:设置持久代大小为16m.
-XX:MaxTenuringThreshold=0:设置垃圾最大年龄.如果设置为0的话,则年轻代对象不经过Survivor区,直接进入年老代. 对于年老代比较多的应用,可以提高效率.如果将此值设置为一个较大值,则年轻代对象会在Survivor区进行多次复制,这样可以增加对象再年轻代的存活 时间,增加在年轻代即被回收的概论.
Java 对象模型
问:oop-klass、对象头?
答:对象头:对象头包括两部分信息分别是Mark World和元数据指针,Mark World用于存储对象运行时的数据,比如HashCode、锁状态标志、GC分代年龄等。而元数据指针用于指向方法区的中目标类的类型信息,通过元数据指针可以确定对象的具体类型。
HotSpot中采用了OOP-Klass模型,它是用来描述Java对象实例的一种模型,OOP(Ordinary Object Pointer)指的是普通对象指针,而Klass用来描述对象实例的具体类型。
虚拟机性能监控与故障处理工具
jps, jstack, jmap, jstat, jconsole, jinfo, jhat, javap, btrace, TProfiler
Arthas。