JVM学习笔记——常见面试题

Java虚拟机,平台无关的编程语言?

Java虚拟机是一个可以执行java字节码的虚拟机进程。Java源文件被编译成能被java虚拟机执行的字节码文件。
Jvm是运行在操作系统之上的,每个操作系统的指令是不同的,JDK是区分操作系统的,只要你在本地装了JDK,这个jdk就可以和当前系统兼容。
Class字节码运行在虚拟机之上,就不需要担心class字节码在哪个操作系统编译的,只要符合操作规范就可以运行。
所以java做到了跨平台的,编译一次,在任何平台都可以运行。

JVM加载class文件的原理机制

Java类的加载是动态的。他不回一次性将所有类加载后再运行,他是保证运行的基础类完全加载到虚拟机中,至于其他的类,需要用的时候再加载,节省内存开销。
JVM加载过程:装载、链接、初始化
双亲委派模型:启动类加载器,扩展类加载器、应用程序类加载器
工作过程:如果一个类加载器收到了类加载的请求,他首先不会自己去尝试加载这个类,而是把它委派给父类加载器去完成,每一个层次的类加载器都是如此,所以所有的加载请求最终都传递到了顶层的启动类加载器中,只有当父类加载器反馈自己没有办法完成这个请求的时候,子类加载器会尝试去自己加载。
1.装载:查找和导入class文件;
2.连接:
(1)检查:检查载入的class文件数据的正确性;
(2)准备:为类的静态变量分配存储空间;
(3)解析:将符号引用转换成直接引用(这一步是可选的)
3.初始化:初始化静态变量,静态代码块、(5种必须初始化的:反射的方式。初始化某个子类其父类也会被初始化,被标明是启动类(主函数),使用jdk1.7的动态语言。)

JVM内存划分

栈区:隔离的
java虚拟机栈本地方法栈
每个方法执行都会创建一个帧栈,用于存放局部变量表,操作栈,动态链接,方法出口等。每个方法从被调用,直到被执行完。对应着一个栈帧在虚拟机中从入栈到出栈的过程。
堆区:共享的
堆被所有线程共享区域,在虚拟机启动时创建,唯一目的存放对象实例
堆区是gc的主要区域,通常情况下分为两个区块
年轻代年老代**。更细一点年轻代又分为Eden区最要放新创建对象,From survivor 和 To survivor 保存gc后幸存下的对象,默认情况下各自占比 8:1:1。*。
方法区:共享的
被所有线程共享区域,用于存放被虚拟机加载的类信息,常量,静态变量等数据,被Java虚拟机描述为堆的一个逻辑部分。习惯是也叫它永久代。
gc很少光顾这个区域,不过也是需要回收的,主要针对常量池回收类型卸载
常量池用于存放编译期生成的各种字节码和符号引用,常量池具有一定的动态性,里面可以存放编译期生成的常量;运行期间的常量也可以添加进入常量池中,比如string的intern()方法。

程序计数器:当前线程锁执行的信号指示器,通过改变计数器的值来确定下一条指令,比如:循环,分支,跳转,异常处理,线程恢复等都是依赖计数器来完成。
堆里面的分区:Eden,survivalfrom to,老年代,各自的特点。
1.JVM中堆空间可以分成三个大区,新生代、老年代、永久代。
2.新生代可以划分为三个区,Eden区,两个幸存区。
在JVM运行时,可以通过配置以下参数改变整个JVM堆的配置比例
1.JVM运行时堆的大小
-Xms堆的最小值
-Xmx堆空间的最大值
2.新生代堆空间大小调整
  -XX:NewSize新生代的最小值
  -XX:MaxNewSize新生代的最大值
  -XX:NewRatio设置新生代与老年代在堆空间的大小
  -XX:SurvivorRatio新生代中Eden所占区域的大小
3.永久代大小调整
 -XX:MaxPermSize

栈和堆的区别

1.栈有系统自动分配
2.堆需要程序员自己申请并指明大小

Java虚拟机,平台无关的编程语言?

Java虚拟机是一个可以执行java字节码的虚拟机进程。Java源文件被编译成能被java虚拟机执行的字节码文件。
Jvm是运行在操作系统之上的,每个操作系统的指令是不同的,JDK是区分操作系统的,只要你在本地装了JDK,这个jdk就可以和当前系统兼容。
Class字节码运行在虚拟机之上,就不需要担心class字节码在哪个操作系统编译的,只要符合操作规范就可以运行。
所以java做到了跨平台的,编译一次,在任何平台都可以运行。

垃圾回收机制及算法

1.引用计数法:当引用数为0时,对象死亡
2.根搜索算法:根对象到某对象不可达时,对象死亡
期中5,6,7对象不可达时,及即为死亡。
程序员对垃圾回收机制只有使用权,没有控制权。
老年代通常使用算法:标记-清除算法、标记-整理算法
新年代通常使用算法:复制算法

垃圾回收的算法:

引用计数 :原理是此对象有一个引用,即增加一个计数,删除一个引用则减少一个计数。垃圾回收时,只用收集计数为 0 的对象。此算法最致命的是无法处理循环引用的问题;
标记-清除 :此算法执行分两阶段。第一阶段从引用根节点开始标记所有被引用的对象,第二阶段遍历整个堆,把未标记的对象清除;
此算法需要暂停整个应用,同时,会产生内存碎片;
复制算法 :效率高,但是需要占2倍内存
标记-整理 :此算法结合了 “标记-清除” 和 “复制” 两个算法的优点。也是分两阶段,第一阶段从根节点开始标记所有被引用对象,第二阶段遍历整个堆,把清除未标记对象并且把存活对象 “压缩” 到堆的其中一块,按顺序排放。
此算法避免了 “标记-清除” 的碎片问题,同时也避免了 “复制” 算法的空间问题。

root 搜索算法中,哪些可以作为 root?

被启动类(bootstrap 加载器)加载的类和创建的对象;
JavaStack 中的引用的对象 (栈内存中引用的对象);
方法区中静态引用指向的对象;
方法区中常量引用指向的对象;
Native 方法中 JNI 引用的对象。

GC 什么时候开始?

GC分为两部分:GC:收集新生代的区域;Full GC:收集新生代和老年代的区域。
GC发生在堆区,堆区还可以细分为新生代、老年代,新生代还分为一个 Eden 区和两个 Survivor 区。
对象优先在 Eden 中分配,当 Eden 中没有足够空间时,虚拟机将发生一次 Minor GC,因为 Java 大多数对象都是朝生夕灭,所以 Minor GC 非常频繁,而且速度也很快;
Full GC,发生在老年代的 GC,当老年代没有足够的空间时即发生 Full GC,发生 Full GC 一般都会有一次 Minor GC。
大于PretenureSizeThreadhold这个参数的时候,令对象直接在老年代中分配,避免在 Eden 区和两个 Survivor 区发生大量的内存拷贝;

内存泄漏和内存溢出

内存溢出:指的是内存不够用了;
内存泄漏:是指对象可达,但是没用了。就是本该被 GC 回收的对象并没有被回收;
内存泄露是导致内存溢出的原因之一;内存泄露积累起来将导致内存溢出。
内存泄露大到一定程度会导致内存溢出。但是内存溢出不一定是内存泄露引起的。

内存泄漏的原因分析:

1.内存中加载的数据量过于庞大,如一次从数据库取出过多数据;
2.集合类中有对对象的引用,使用完后未清空,使得JVM不能回收;
3.代码中存在死循环或循环产生过多重复的对象实体;
4.使用的第三方软件中的BUG;
5.启动参数内存值设定的过小

内存溢出解决方案

修改JVM启动参数,直接增加内存;检查错误日志;对代码进行走查和分析,找出内存可能发生的位置。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值