文档章节

JVM 面试

Original123
 Original123
发布于 2017/03/17 15:31
字数 2615
阅读 26
收藏 0

1、内存模型以及分区,需要详细到每个区放什么。

通俗的说,

Java 虚拟机具有一个堆,堆是运行时数据区域,所有类实例和数组的内存均从此处分配。

JVM主要管理两种类型内存:堆和非堆,堆内存(Heap Memory)是在 Java 虚拟机启动时创建,非堆内存(Non-heap Memory)是在JVM堆之外的内存。

简单来说,堆是Java代码可及的内存,留给开发人员使用的;非堆是JVM留给自己用的,包含方法区、JVM内部处理或优化所需的内存(如 JIT Compiler,Just-in-time Compiler,即时编译后的代码缓存)、每个类结构(如运行时常数池、字段和方法数据)以及方法和构造方法的代

JVM 内存包含如下几个部分:

堆内存(Heap Memory): 存放Java对象
非堆内存(Non-Heap Memory): 就是我们平时说的方法取,存放类加载信息和其它meta-data
其它(Other): 存放JVM 自身代码等


在JVM启动时,就已经保留了固定的内存空间给Heap内存,这部分内存并不一定都会被JVM使用,但是可以确定的是这部分保留的内存不会被其他进程使用,这部分内存大小由-Xmx 参数指定。而另一部分内存在JVM启动时就分配给JVM,作为JVM的初始Heap内存使用,这部分内存是由 -Xms 参数指定。

Java文件经过JVM编译成class文件,通过类加载器,加载到内存中.

JVM内存模型按内存线程是否共享分为主内存和私有内存,

主内存:

    堆(Heap):Java除了栈区,几乎所有的java对象都是存储在堆区.

    方法区: 就是上述说的非堆,1,加载类时的类的信息,2,final常量,3,静态变量,

私有内存:

    虚拟机栈:

        虚拟机栈,生命周期与线程相同,是Java方法执行的内存模型。每个方法(不包含native方法)执行的同时都会创建一个栈帧结构,方法执行过程,对应着虚拟机栈的入栈到出栈的过程。

    本地方法栈:本地方法栈则为虚拟机使用到的Native方法提供内存空间

    程序计数器: 程序计数器PC,当前线程所执行的字节码行号指示器。每个线程都有自己计数器,是私有内存空间,该区域是整个内存中较小的一块。

1,线程正在执行一个Java方法时,PC计数器记录的是正在执行的虚拟机字节码的地址;

2,当线程正在执行的一个Native方法时,PC计数器则为空(Undefined)。

一句话概括:'

堆:存放大部分java对象;

方法区:存放加载累的基本信息,final值和静态变量.

本地方法栈:虚拟机使用Native方法的内存空间

虚拟机栈:Java中方法的内存模型,代表着方法的出战入栈

程序计数器:Java运行的字节码地址.

各个分区出现的异常:

 

几个JVM参数说明:

 

-Xms:JVM启动时初始分配给JVM的内存,当JVM内存低于总内存40%,此时JVM内存会达到该值得最大值.

-Xmx:分配给JVM堆内存的值.

outofMemory 代码示例:

 

1,堆区:

public static void main(String[] args) {
		//-Xms20M -Xmx20M -XX:+HeapDumpOnOutOfMemoryError
		List<Integer> list = new ArrayList<Integer>();
		while(true){
			list.add(9);
		}
		
		
		
	}

显示结果:

java.lang.OutOfMemoryError: Java heap space
Dumping heap to java_pid14249.hprof ...
Heap dump file created [15664339 bytes in 0.049 secs]
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
	at java.util.Arrays.copyOf(Arrays.java:3210)
	at java.util.Arrays.copyOf(Arrays.java:3181)
	at java.util.ArrayList.grow(ArrayList.java:261)
	at java.util.ArrayList.ensureExplicitCapacity(ArrayList.java:235)
	at java.util.ArrayList.ensureCapacityInternal(ArrayList.java:227)
	at java.util.ArrayList.add(ArrayList.java:458)
	at com.outofmemoryerror.App.main(App.java:15)

 

2,虚拟机栈和本地方法栈溢出;

private int stackLength = 1;
	public void increase(){
		stackLength++;
		increase();
	}
	//-Xss160k  设置虚拟机栈大小160k
	public static void main(String[] args) throws Throwable{
		
		JavaStackOOM oom = new JavaStackOOM();
		
		try {
			oom.increase();
		} catch (Throwable e) {
			System.out.println("oom.stackLength is:"+oom.stackLength);
			throw e;
		}
		
		
	}

异常信息如下:

oom.stackLength is:771Exception in thread "main" 

java.lang.StackOverflowError

at xxxx

3,方法区常量池:

// -XX:PermSize=10M -XX:MaxPermSize=10M
	
	public static void main(String[] args) {
		
		List<String> list = new ArrayList<String>();
		int i=0;
		while(true){
			list.add(String.valueOf(i++).intern());
		}
		
		
	}

上述代码在jdk6以前会出现异常,在jdk7以后该异常不会出现.

在JDK1.7中, 已经把原本放在永久代的字符串常量池移出, 放在堆中. 为什么这样做呢? 因为使用永久代来实现方法区不是个好主意, 很容易遇到内存溢出的问题. 我们通常使用PermSize和MaxPermSize设置永久代的大小, 这个大小就决定了永久代的上限, 但是我们不是总是知道应该设置为多大的, 如果使用默认值容易遇到OOM错误.

JVM的实现中将类的元数据放入 native memory, 将字符串池和类的静态变量放入java堆中

2、堆里面的分区:Eden,survival (from+ to),老年代,各自的特点。

 

 

 

 

 

 

 

 

 

 


3、对象创建方法,对象的内存分配,对象的访问定位。

对象的创建

我们都知道java语言中是用new关键字来创建对象的,然而在虚拟机中创建对象的过程是怎样的呢?

当虚拟机遇到一条new指令时,首先会去检查这个指令的参数是否能在常量池中定位到这个类的符号引用,并且坚持这个符号引用对应的类是否已经加载,解析,初始化如果没有的话,必须先执行相应类的加载。

类加载检查之后,虚拟机就要为新生的对象分配内存,为对象分配内存空间相当于在java堆中开辟一块和新生对象一样大小的内存。

内存分配之后,虚拟机将分配到内存的空间初始化,这一操作为了保证对象的实例字段在未被赋初始值就可以使用。接下来就要对对象就行必要的设置,例如,此对象属于哪个类,对象的哈希码,这些对象存放在对象的对象头中。在这些操作完成之后,从虚拟机的角度看,一个对象已经创建完成,但是从Java程序来看,真正的创建才刚开始,去执行init()方法。对象按照我们的意愿初始化完之后,一个对象就算真正的创建完成了。

对象的内存布局

在HotSpot虚拟机中,对象在内存中存储的布局可以分为3部分:对象头,实例数据和对齐数据。

对象头中包括两部分信息,一部分用于存储对象自身的运行时数据,如哈希码,锁状态标志等;另一部分时类型指针,即对象指向它的类元数据的指针,虚拟机就是通过此指针来确定这个对象属于哪个类的实例。

实例数据时对象真正存储的有效信息,也是在程序中定义的各个字段的内容,至于这部分的存储顺序是由虚拟机的分配策略和在Java中中定义的顺序决定的,其中父类中定义的变量一定会出现在子类定义的变量之前。

对象对齐填充,其实它并不一定存在,在Hot Spot在虚拟机的内存管理系统要求对象起始位置的大小必须是8字节的整数倍,所以当对象实例数据部分没有对齐,就需要对齐补充来补全。

对象的访问定位

在Java程序中我们用栈上的reference数据访问堆上的对象。在Java虚拟机规范中规定reference也只是一个指向对象的引用,但是具体但是如何定位,访问堆中对象的具体位置,不同的虚拟机实现方式是不一样的。常用的访问方式有句柄和直接指针两种。

如果使用句柄访问,Java堆中首先划分出一块内存作为句柄池,reference中存储的是句柄的地址,而句柄中存储的是对象实例数据和类型数据的地址信息。

如果使用直接指针访问,reference中存储的就是对象的地址,而Java堆对象的布局中就必须考虑如何放置访问堆对象的信息。


4、GC的两种判定方法:
5、GC的三种收集方法:标记清除、标记整理、复制算法的原理与特点,分别用在什么地方,如果让你优化收集方法,有什么思路?
6、GC收集器有哪些?CMS收集器与G1收集器的特点。
7、Minor GC与Full GC分别在什么时候发生?
8、几种常用的内存调试工具:jmap、jstack、jconsole。
9、类加载的五个过程:
10、双亲委派模型:Bootstrap ClassLoader、Extension ClassLoader、ApplicationClassLoader。
11、双亲委派模型是某个特定的类加载器在接到加载类的请求时,首先将加载任务委托给父类加载器,依次递归,如果父类加载器可以完成类加载任务,就成功返回;只有父类加载器无法完成此加载任务时,才自己去加载。-----例如类java.lang.Object,它存在在rt.jar中,无论哪一个类加载器要加载这个类,最终都是委派给处于模型最顶端的Bootstrap ClassLoader进行加载,因此Object类在程序的各种类加载器环境中都是同一个类。相反,如果没有双亲委派模型而是由各个类加载器自行加载的话,如果用户编写了一个java.lang.Object的同名类并放在ClassPath中,那系统中将会出现多个不同的Object类,程序将混乱
12、分派:静态分派(重载)与动态分派(重写)。
13、你知道哪些JVM性能调优
14,JVM运行内存的分类
15,Java内存堆和栈区别
16,GC回收机制
17,GC 标记对象的死活
18,GC 回收算法
19,MinorGC&FullGC
20,Java 堆内存的分配策略
21,Class 的加载过程
22,类加载器
23,自定义ClassLoader
24,双亲委派模型&打破双亲委派模型
25,引起类初始化操作的四个行为

© 著作权归作者所有

Original123
粉丝 7
博文 66
码字总数 87205
作品 0
徐汇
架构师
私信 提问
15个顶级Java多线程面试题及回答

Java 线程面试问题 在任何Java面试当中多线程和并发方面的问题都是必不可少的一部分。如果你想获得任何股票投资银行的前台资讯职位,那么你应该准备很多关于多线程的问题。在投资银行业务中多...

LCZ777
2014/05/27
641
0
java中高级大公司多线程面试题

1)在Java中Lock接口比synchronized块的优势是什么?你需要实现一个高效的缓存,它允许多个用户读,但只允许一个用户写,以此来保持它的完整性,你会怎样去实现它? lock接口在多线程和并发编...

java成功之路
2018/10/30
0
0
提给程序员和开发者的 10 道 Java 泛型面试题

关于泛型的面试题在 Java面试中变得越来越常见,因为 Java 5问世已经有相当长的时间了,越来越多的应用已经迁移到Java 5上来了,并且几乎所有新的Java开发工作也都是在Tiger(Java 5的项目代号...

lwei
2013/10/18
13.6K
30
阿里巴巴菜鸟Java一面11个问题,你会几个呢?

近日,w3cschool app开发者头条上分享了阿里菜鸟Java程序员一些面试题。 这吸引了不少程序员小伙伴们的注意。 在分享阿里菜鸟Java程序员面经前,来看下Java面试一些面试经验分享: 0、Java高...

W3Cschool
2018/04/03
0
0
Java 200+ 面试题补充 ThreadLocal 模块

让我们每天都有进步,老王带你打造最全的 Java 面试清单,认真把一件事做到极致。 本文是前文《Java 最常见的 200+ 面试题》的第一个补充模块。 1.ThreadLocal 是什么? ThreadLocal 是一个本...

王磊的博客
03/08
670
0

没有更多内容

加载失败,请刷新页面

加载更多

关于AsyncTask的onPostExcute方法是否会在Activity重建过程中调用的问题

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。 本文链接:https://blog.csdn.net/XG1057415595/article/details/86774575 假设下面一种情况...

shzwork
今天
6
0
object 类中有哪些方法?

getClass(): 获取运行时类的对象 equals():判断其他对象是否与此对象相等 hashcode():返回该对象的哈希码值 toString():返回该对象的字符串表示 clone(): 创建并返此对象的一个副本 wait...

happywe
今天
6
0
Docker容器实战(七) - 容器中进程视野下的文件系统

前两文中,讲了Linux容器最基础的两种技术 Namespace 作用是“隔离”,它让应用进程只能看到该Namespace内的“世界” Cgroups 作用是“限制”,它给这个“世界”围上了一圈看不见的墙 这么一...

JavaEdge
今天
8
0
文件访问和共享的方法介绍

在上一篇文章中,你了解到文件有三个不同的权限集。拥有该文件的用户有一个集合,拥有该文件的组的成员有一个集合,然后最终一个集合适用于其他所有人。在长列表(ls -l)中这些权限使用符号...

老孟的Linux私房菜
今天
7
0
面试套路题目

作者:抱紧超越小姐姐 链接:https://www.nowcoder.com/discuss/309292?type=3 来源:牛客网 面试时候的潜台词 抱紧超越小姐姐 编辑于 2019-10-15 16:14:56APP内打开赞 3 | 收藏 4 | 回复24 ...

MtrS
今天
6
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部