面试题

Java内存区域

2019-06-24  本文已影响6人  wuhuaguo丶

主要面试题:
介绍下Java内存区域
Java对象创建的步骤(五步,需要知道JVM分别做了什么)
对象访问定位的两种方式
不同的变量在Java内存区域中存放的位置(局部变量、静态变量、类的成员变量)
OOM异常


堆:此内存区域的唯一目的就是存放对象实例,几乎所有的对象实例以及数组都在这里分配内存。
栈:主要存放编译器可知的各种数据类型(boolean、byte、char、short、int、float、long、double)、对象引用(reference 类型,它不同于对象本身,可能是一个指向对象起始地址的引用指针,也可能是指向一个代表对象的句柄或其他与此对象相关的位置)
方法区:它用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。值得注意的是在方法区中存在一个叫运行时常量池(Runtime Constant Pool)的区域,它主要用于存放编译器生成的各种字面量和符号引用,这些内容将在类加载后存放到运行时常量池中,以便后续使用。
程序计数器作用:
  1. 字节码解释器通过改变程序计数器来依次读取指令,从而实现代码的流程控制,如:顺序执行、选择、循环、异常处理。
  2. 在多线程的情况下,程序计数器用于记录当前线程执行的位置,从而当线程被切换回来的时候能够知道该线程上次运行到哪儿了。

全局变量也就是类的成员变量在堆里
静态常量在方法区中
局部变量在虚拟机栈里
成员变量、类变量、局部变量的区别


线程私有的:

线程共享的:


内存溢出异常:

内存泄漏与内存溢出
内存溢出:java.lang.OutOfMemoryError,是指程序在申请内存时,没有足够的内存空间供其使用,出现OutOfMemoryError。
产生原因
产生该错误的原因主要包括:
1.JVM内存过小。
2.程序不严密,产生了过多的垃圾。
内存泄漏:Memory Leak,是指程序在申请内存后,无法释放已申请的内存空间,一次内存泄露危害可以忽略,但内存泄露堆积后果很严重,无论多少内存,迟早会被占光。
在Java中,内存泄漏就是存在一些被分配的对象,这些对象有下面两个特点:
1)首先,这些对象是可达的,即在有向图中,存在通路可以与其相连;
2)其次,这些对象是无用的,即程序以后不会再使用这些对象。
如果对象满足这两个条件,这些对象就可以判定为Java中的内存泄漏,这些对象不会被GC所回收,然而它却占用内存。
关于内存泄露的处理页就是提高程序的健壮型,因为内存泄露是纯代码层面的问题。
一个Java内存泄漏的排查案例


1. 类加载检查

当JVM遇到一条new指令时,会去检查这个指令的参数是否能在常量池中定位到一个类的符号引用,并且检查这个符号引用代表的类是否已被加载、解析和初始化过。如果没有,就先执行类加载过程。

2. 分配内存

当在类加载完成之后,JVM就会为新生对象分配内存,对象所需内存的大小在类加载完成之后就可以完全确定,为对象分配空间的任务等同于把一块确定大小的内存从Java堆中划分出来。分配方式有两种“指针碰撞”“空闲列表”选择哪种分配内存的方式由Java堆是否规整决定,而Java堆是否规整又由采用的垃圾收集器是否带有压缩整理功能决定。


内存分配并发问题
在创建对象的时候有一个很重要的问题,就是线程安全,因为在实际的开发中,创建对象是很频繁的事情,对于虚拟机来说,必须要保证创建过程是线程安全的,通常来讲,虚拟机由两种方案来保证线程安全。
3. 初始化零值

内存分配完成后,JVM需要将分配到的内存空间都初始化为零值(不包括对象头)

4. 设置对象头

对对象进行必要的设置

5. 执行init方法

在上面工作都完成之后,从虚拟机的视角来看,一个新的对象已经产生了,但从 Java 程序的视角来看,对象创建才刚开始,<init> 方法还没有执行,所有的字段都还为零。所以一般来说,执行 new 指令之后会接着执行 <init> 方法,把对象按照程序员的意愿进行初始化,这样一个真正可用的对象才算完全产生出来。


对象的访问定位

建立对象是为了使用对象,我们的Java程序需要通过栈上的reference数据来操作堆上的具体对象。对象的访问方式有虚拟机实现而定,目前主流的访问方式有①使用句柄和②直接指针两种:

  1. 句柄: 如果使用句柄的话,那么 Java 堆中将会划分出一块内存来作为句柄池,reference 中存储的就是对象的句柄地址,而句柄中包含了对象实例数据与类型数据各自的具体地址信息;


  2. 直接指针: 如果使用直接指针访问,那么 Java 堆对象的布局中就必须考虑如何放置访问类型数据的相关信息,而 reference 中存储的直接就是对象的地址。



    这两种对象访问方式各有优势。使用句柄来访问的最大好处是 reference 中存储的是稳定的句柄地址,在对象被移动时只会改变句柄中的实例数据指针,而 reference 本身不需要修改。使用直接指针访问方式最大的好处就是速度快,它节省了一次指针定位的时间开销。
    HotSpot虚拟机使用的是直接指针的方式。

上一篇下一篇

猜你喜欢

热点阅读