深入理解java虚拟机

目录

为什么要学java虚拟机。

  1. 面试经常问
  2. 想自定义类加载器
  3. 前端用户使用时,响应时间过长
  4. 服务器内存不足
  5. CPU超负荷
  6. 程序死锁了

java技术体系包括:程序设计语言、java虚拟机、()、()、()。

class文件格式、api类库、第三方java类库

自己编译jdk有不少开源jdk可供选择,如Apache harmony、()。

openJDK

获取jdk源码方式:git clone from repository、()。

下载压缩包,而且压缩包下载速度更快

函数式编程有一个重要优点:(),对java语言在多核时代保持主流语言帮助很大。

天然支持并发运行

把java程序设计语言、()、()统称为jdk。

java虚拟机、javaAPI类库

jdk和jre区别

jre只有虚拟机和API两部分

java和c++之间有一堵由()和()围成的高墙,墙外面的人想进来墙里面的人想出去。

内存动态分配、垃圾收集

程序计数器可以看做()、为了线程切换可以()

当前线程的行号指示器、恢复到正确的执行位置

虚拟机栈描述的是()执行的内存模型,每个方法执行都会创建一个()。

栈帧

虚拟机栈规定了两种异常()、()

stackoverflow、outofmemory

虚拟机栈和本地方法栈的区别

唯一区别是本地方法栈为native方法服务

java堆区域唯一目的

存放对象实例

垃圾收集器管理的主要区域是()

java堆

栈、堆、方法区、线程计数器,哪些是线程共享的

只有堆跟方法区是线程共享的

方法区用于存储类信息、()、()

常量、静态变量

方法区内存回收的目标主要针对()、()

常量池的回收和类型的卸载

遇到一条new指令时首先检查常量池();接下来为新生对象(),指针碰撞与空闲列表区别(),选择哪种方式是由(A)决定的,而A由()决定;内存分配完成后,虚拟机(),这一步保证了对象实例字段可以不赋初始值就可直接使用。

参数能否定位到这个类的符号引用,如果没有,那么先执行相应的类加载
分配内存
区别是:一个堆内存是规整的,分配内存只需要移动指针,叫做指针碰撞,另一个内存不规整,维护一个列表记录哪些内存可用,叫做空闲列表
java堆是否规整决定
垃圾收集器是否带有压缩整理功能决定
虚拟机会将分配到的内存空间都初始化为零值

怎么设置java堆大小不可扩展

-Xmx设置最大值、-Xms设置最小值,最大值和最小值设置为相等即可

写一段堆内存溢出的代码

		List l = new ArrayList();
        while (true) {
            l.add(new Object());
        }

要解决OOM异常,先通过()工具分析,重点是要确认(),也就是要分清是出现了()还是();如果是出现了内存泄漏,可进一步查看(),如果不是内存泄漏,那对象必须存活,应当检查()与()是否可以调大,从代码上检查是否存在某些对象()

内存映像分析工具
内存中的对象是否是必要的
是出现了内存泄漏还是内存溢出
查看泄漏对象到GC Root的引用链
虚拟机的堆参数与物理内存是否可以调大
生命周期过长

虚拟机栈的两种异常原因stackoverflowError、outofmemoryError

线程请求栈深度大于虚拟机所允许的最大深度
虚拟机扩展栈时无法申请到足够内存

设置栈内存容量参数

-Xss

减少栈的内存容量,是抛出stackoverflow、outofmemory哪种异常,怎么抛出outofmemoryError

stackoverflow
无限制地创建线程

写一段导致常量池内存溢出的代码,string的intern方法作用是()

		List<String> l = new ArrayList<>();
        int i = 0;
        while (true){
            l.add(String.valueOf(i++).intern());
        }

intern将string对象包含的字符串添加到常量池中

unsafe类的getunsafe方法限制了只有()类加载器才能返回实例,也就是设计者希望只有()中的类才能使用unsafe功能

引导类加载器
rt.jar中的类

GC需要完成的三件事情

哪些内存需要回收
什么时候回收
如何回收

为什么栈不需要内存GC

栈中的栈帧随着方法的进入和退出有条不紊地执行着出栈和入栈的操作,每一个栈帧中分配多少内存基本上在类结构确定下来就已知的,方法结束或线程结束时,内存自然就跟着回收了

引用计数法

给对象添加一个计数器,计数器为0的对象就是不可能再被使用

java虚拟机为什么没有选用引用计数器方法

因为他很难解决对象之间相互寻欢引用的问题

可达性分析法

GC Root对象作为起始点,当一个对象到GC Root没有任何引用链相连,证明此对象不可以用

可作为GC Root对象的对象包括()、()、()

虚拟机栈中引用的对象
方法区类静态变量引用的对象
方法区中常量引用的对象

软用与弱引用都是用来描述一些()的对象,区别是()

有用非必须的对象
软引用只有在内存不足时才会被回收,弱引用的对象只能生存到下一次垃圾收集之前

标记清除算法主要不足:效率问题(),空间问题()

标记和清除效率都不高
会产生内存碎片,有大对象的时候容易触发垃圾收集动作

复制算法:不用考虑()问题,代价是()

内存碎片
可用内存缩小为原来一半

商用虚拟机都采用()回收新生代

复制算法

回收新生代的复制算法会按1:1回收空间吗?为什么?如果不是那默认比率是多少

不会
新生代对象朝生夕死
默认8:1,一个Eden区和两个survivor区

当survivor内存不够用时,需要()

老年代内存进行分配担保

为什么老年代不能选用复制算法

老年代对象存活率高,也没有额外空间对他进行分配担保

老年代选用什么算法回收内存

标记清理或标记整理

内存分配与回收策略:对象优先在()区分配、()直接进入老年代、()对象将进入老年代

Eden区
大对象
长期存活的对象

当Eden区没有足够的空间分配时,虚拟机触发一次()

minor GC

设置java堆大小20M,10M分配给新生代;设置Eden区与一个survivor区比例为8:1

-Xms20M、-Xmx20M、-Xmn10M
-XX:SurvivorRatio=8

新生代minorGc与老年代fullGc有什么不同

minorGc比较频繁,速度也快
fullGc速度慢10倍以上

大对象指的是(),比出现大对象更糟糕的是()

大量连续内存空间的对象,很长的字符串以及数组
朝生夕死的大对象

虚拟机提供了()参数,另大于这个值得对象直接去老年代分配,这样做的目的是()

-XX:PretenureSizeThreshold=3145728
避免Eden区与survivor区发生大量内存复制

什么是长期存活的对象,怎么设置晋升到老年代的年龄阈值

经过一次minorGc年龄加1,默认为15
-XX:MaxTenuringThreshold=15

jdk的可视化工具()、VisualVM

jconsole

怎么启动jconsole

bin目录下的jconsole.exe

常用jconsole来()、()

内存监控、线程监控

线程监控:有这样几个线程,main线程在等待system.in的输入、死循环、活锁、死锁,比较他们的状态、阻塞总数、等待总数

活锁状态为waiting、死锁为blocked,其余为running
死锁阻塞总数为1,其余为0
等待总数,活锁为1,其余为0

死锁了,可以用()检测

jconsole的线程页签,有个死锁检测按钮

string a = "a"占多少字节,string b="汉"占多少字节,short s=5,占多少字节,byte、short、int各占多少字节,表示数值范围多少

a占一个字节,汉占3个字节,byte是一个字节8位,所以数值范围是2^8,short是两个字节,int是4个字节

String s = "中";
// gbk占两个字节,utf-8占三个字节
byte[] bytes = s.getBytes("GBK");

为什么超大堆中难有fullGc

对象的生存周期是请求级或者页面级的,会话级和全局级的长生命对象少。对象朝生夕死

main方法输出什么,会输出subclass init吗

public class SuperClass {
    static {
        System.out.println("super class init");
    }
    
    public static int value = 123;
}
public class SubClass extends SuperClass {
    static {
        System.out.println("subclass init");
    }
}
	public static void main(String[] args) {
        System.out.println(SubClass.value);
    }

不会输出subclass init

会输出constclass init吗

public class ConstClass {
    static {
        System.out.println("constclass init");
    }

    public static final String HELLO = "hello world";
}
	public static void main(String[] args) {
        System.out.println(ConstClass.HELLO);
    }

不会

object instanceof Class,在哪种情况下可能会是false

不同的类加载器,加载同一个class文件得出来的class对象不是同一个

启动类加载器负责加载()中的类库

java_home/lib下

扩展类加载器加载()类库

java_home/lib/ext目录

应用程序类加载器负责加载()类库

用户类路径

双亲委派模型工作过程是

如果一个类加载器收到了类加载的请求,首先不会自己去尝试加载这个类,而是委派给父类夹杂器完成,当父类加载器无法完成这个请求时(搜索范围中没有这个类),子类加载器才会尝试自己去加载

ClassLoader类的常用方法

URL url = classLoader.getResource("person.properties");
InputStream resourceAsStream = classLoader.getResourceAsStream("person.properties");
java.nio.file.Path path = java.nio.file.Paths.get(new URI(""));
byte[] cLassBytes = cLassBytes = java.nio.file.Files.readAllBytes(path);
Class clazz = classLoader.defineClass("name", cLassBytes, 0, cLassBytes.length);
Class clazz = classLoader.loadClass(“”)

虚拟机性能监控与故障处理工具

虚拟机运行产生的数据有哪些

答:




运行日志、异常堆栈、GC日志、线程快照(threadDump/Javacore文件)、堆转储快照(headDump/hprof文件)等

你所知道的bin目录下的工具有哪些

答:





Java.exe、Javac.exe、jmap

jdk工具的功能代码主要是在()实现的

答:




jdk/lib/tools.jar类库

进程的本地虚拟机唯一ID又叫()。查本地虚拟机各进程唯一ID,可以使用工具()

答:



local Virtual machine identifier(LVMID)
jps

jps英文全称(),作用是()

答:





jvm process status tool
可以列出正在运行的虚拟机进程,并显示虚拟机执行主类(Main Class,main方法所在的类)名称,以及这些进程的本地虚拟机唯一ID

jps使用

答:



命令格式:
jps [options] [hostID]

执行样例:
jps -l

如何理解hostID与options

options可有-l :输出主类全名,如果进程执行的是jar包,输出jar路径。。。

hostID为RMI注册表中注册的主机名

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值