目录介绍
-
01.Java对象的建立过程php
- 1.0 看下建立类加载过程
- 1.1 对象的建立
- 1.2 对象的内存布局
-
02.Java内存区域java
- 2.0 运行时数据区域
- 2.1 程序计数器
- 2.2 虚拟机栈
- 2.3 本地方法栈
- 2.4 Java堆
- 2.5 方法区
- 2.6 运行时常量池
- 2.7 直接内存
-
03.Java对象的访问定位方式git
-
04.Java对象销毁分析程序员
- 4.1 JVM内存分配与回收
- 4.2 判断对象是否死亡
- 4.3 不可达的对象并不是“非死不可”
- 4.4 如何判断一个常量是废弃常量
- 4.5 如何判断一个类是无用的类
- 4.6 GC回收算法详解
-
05.String类和常量池github
- 5.1 String对象的两种建立方式
- 5.2 String类型的常量池
好消息
- 博客笔记大汇总【16年3月到至今】,包括Java基础及深刻知识点,Android技术博客,Python学习笔记等等,还包括平时开发中遇到的bug汇总,固然也在工做之余收集了大量的面试题,长期更新维护而且修正,持续完善……开源的文件是markdown格式的!同时也开源了生活博客,从12年起,积累共计47篇[近20万字],转载请注明出处,谢谢!
- 连接地址:https://github.com/yangchong2...
- 若是以为好,能够star一下,谢谢!固然也欢迎提出建议,万事起于忽微,量变引发质变!
问题思考答疑
- 说一下建立一个对象,类的加载过程。类信息,常量,变量,方法分别放到内存中哪里?
- 对于运行时数据区域,哪些是私有的,哪些是共享的,为何要这样设计?
- 程序计数器会出现OOM吗?它的生命周期是怎么样的?
- 本地方法栈和Java虚拟机栈有什么区别?本地方法栈在什么状况下会形成OOM?
- java堆主要是作什么做用的?
- 什么是类的加载检查,主要检查什么,如何检查呢?
- Java对象访问定位方式有哪些?主要有什么区别?为何说使用指针效率更高?
- String类能够new吗?直接new和赋值的内容有什么区别,分别放在内存中什么地方?
- 如何判断对象是否死亡(两种方法)。若是有不一样方法,那么之间有什么区别?
- 简单的介绍一下强引用、软引用、弱引用、虚引用(虚引用与软引用和弱引用的区别、使用软引用能带来的好处)。
- 如何判断一个常量是废弃常量,如何判断一个类是无用的类?
- 垃圾收集有哪些算法,各自的特色?常见的垃圾回收器有那些?
- HotSpot为何要分为新生代和老年代?
- 介绍一下CMS,G1收集器。Minor Gc和Full GC 有什么不一样呢?
01.Java对象的建立过程
1.1 看下建立类加载过程
-
Person p = new Person()请写一下类的加载过程?面试
1).由于new用到了Person.class,因此会先找到Person.class文件,并加载到内存中;
2).执行该类中的static代码块,若是有的话,给Person.class类进行初始化;
3).在堆内存中开辟空间分配内存地址;
4).在堆内存中创建对象的特有属性,并进行默认初始化;
5).对属性进行显示初始化;
6).对对象进行构造代码块初始化;
7).对对象进行与之对应的构造函数进行初始化;
8).将内存地址付给栈内存中的p变量
1.1 对象的建立
1.2 对象的内存布局
- 在 Hotspot 虚拟机中,对象在内存中的布局能够分为3快区域:对象头、实例数据和对齐填充。
- Hotspot虚拟机的对象头包括两部分信息,第一部分用于存储对象自身的自身运行时数据(哈希吗、GC分代年龄、锁状态标志等等),另外一部分是类型指针,即对象指向它的类元数据的指针,虚拟机经过这个指针来肯定这个对象是那个类的实例。
- 实例数据部分是对象真正存储的有效信息,也是在程序中所定义的各类类型的字段内容。
- 对齐填充部分不是必然存在的,也没有什么特别的含义,仅仅起占位做用。
- 由于Hotspot虚拟机的自动内存管理系统要求对象起始地址必须是8字节的整数倍,换句话说就是对象的大小必须是8字节的整数倍。而对象头部分正好是8字节的倍数(1倍或2倍),所以,当对象实例数据部分没有对齐时,就须要经过对齐填充来补全。
02.Java内存区域
2.0 运行时数据区域
2.1 程序计数器
- 程序计数器:是一个数据结构,用于保存当前正常执行的程序的内存地址。Java虚拟机的多线程就是经过线程轮流切换并分配处理器时间来实现的,为了线程切换后能恢复到正确的位置,每条线程都须要一个独立的程序计数器,互不影响,该区域为“线程私有”。
- 程序计数器是一块较小的内存空间,能够看做是当前线程所执行的字节码的行号指示器。字节码解释器工做时经过改变这个计数器的值来选取下一条须要执行的字节码指令,分支、循环、跳转、异常处理、线程恢复等功能都须要依赖这个计数器来完。
-
程序计数器主要有两个做用:
- 1.字节码解释器经过改变程序计数器来依次读取指令,从而实现代码的流程控制,如:顺序执行、选择、循环、异常处理。
- 2.在多线程的状况下,程序计数器用于记录当前线程执行的位置,从而当线程被切换回来的时候可以知道该线程上次运行到哪儿。
- 注意:程序计数器是惟一一个不会出现OutOfMemoryError的内存区域,它的生命周期随着线程的建立而建立,随着线程的结束而死亡。
2.2 虚拟机栈
2.3 本地方法栈
- 本地方法栈:跟虚拟机栈很像, 虚拟机栈为虚拟机执行 Java 方法 (也就是字节码)服务,而本地方法栈则为虚拟机使用到的 Native 方法服务。 在 HotSpot 虚拟机中和 Java 虚拟机栈合二为一。
- 本地方法被执行的时候,在本地方法栈也会建立一个栈帧,用于存放该本地方法的局部变量表、操做数栈、动态连接、出口信息。
- 方法执行完毕后相应的栈帧也会出栈并释放内存空间,也会出现 StackOverFlowError 和 OutOfMemoryError 两种异常。
2.4 Java堆
2.5 方法区
2.6 运行时常量池
2.7 直接内存
- 直接内存并非虚拟机运行时数据区的一部分,也不是虚拟机规范中定义的内存区域,可是这部份内存也被频繁地使用。并且也可能致使OutOfMemoryError异常出现。
- JDK1.4中新加入的 NIO(New Input/Output) 类,引入了一种基于通道(Channel) 与缓存区(Buffer) 的 I/O 方式,它能够直接使用Native函数库直接分配堆外内存,而后经过一个存储在 Java 堆中的 DirectByteBuffer 对象做为这块内存的引用进行操做。这样就能在一些场景中显著提升性能,由于避免了在 Java 堆和 Native 堆之间来回复制数据。
- 本机直接内存的分配不会收到 Java 堆的限制,可是,既然是内存就会受到本机总内存大小以及处理器寻址空间的限制。
03.Java对象的访问定位方式
- 创建对象就是为了使用对象,咱们的Java程序经过栈上的 reference 数据来操做堆上的具体对象。对象的访问方式有虚拟机实现而定
-
目前主流的访问方式有
-
这两种对象访问方式各有优点。
- 使用句柄来访问的最大好处是 reference 中存储的是稳定的句柄地址,在对象被移动时只会改变句柄中的实例数据指针,而 reference 自己不须要修改。
- 使用直接指针访问方式最大的好处就是速度快,它节省了一次指针定位的时间开销。
3.1 句柄
- 若是使用句柄的话,那么Java堆中将会划分出一块内存来做为句柄池,reference 中存储的就是对象的句柄地址,而句柄中包含了对象实例数据与类型数据各自的具体地址信息;

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

04.Java对象销毁分析
4.1 JVM内存分配与回收
4.2 判断对象是否死亡
4.2.1 引用计数法
-
给对象中添加一个引用计数器,每当有一个地方引用它,计数器就加1;当引用失效,计数器就减1;任什么时候候计数器为0的对象就是不可能再被使用的。
- 这个方法实现简单,效率高,可是目前主流的虚拟机中并无选择这个算法来管理内存,其最主要的缘由是它很难解决对象之间相互循环引用的问题。
- 所谓对象之间的相互引用问题,以下面代码所示:除了对象objA和objB相互引用着对方以外,这两个对象之间再无任何引用。可是他们由于互相引用对方,致使它们的引用计数器都不为0,因而引用计数算法没法通知 GC 回收器回收他们。
public class Test {
Object instance = null;
public static void main(String[] args) {
Test objA = new Test();
Test objB = new Test();
objA.instance = objB;
objB.instance = objA;
objA = null;
objB = null;
}
}
4.2.2 可达性分析算法
4.2.3 再谈引用
- 不管是经过引用计数法判断对象引用数量,仍是经过可达性分析法判断对象的引用链是否可达,断定对象的存活都与“引用”有关。
- JDK1.2之后,Java对引用的概念进行了扩充,将引用分为强引用、软引用、弱引用、虚引用四种(引用强度逐渐减弱)
- 关于四种引用以及源代码分析,能够看个人这篇文章:https://blog.csdn.net/m0_3770...
4.3 不可达的对象并不是“非死不可”
- 即便在可达性分析法中不可达的对象,也并不是是“非死不可”的,这时候它们暂时处于“缓刑阶段”,要真正宣告一个对象死亡,至少要经历两次标记过程;可达性分析法中不可达的对象被第一次标记而且进行一次筛选,筛选的条件是此对象是否有必要执行 finalize 方法。当对象没有覆盖 finalize 方法,或 finalize 方法已经被虚拟机调用过期,虚拟机将这两种状况视为没有必要执行。
- 被断定为须要执行的对象将会被放在一个队列中进行第二次标记,除非这个对象与引用链上的任何一个对象创建关联,不然就会被真的回收。
4.4 如何判断一个常量是废弃常量
4.5 如何判断一个类是无用的类
4.6 GC回收算法详解
05.String类和常量池
5.1 String对象的两种建立方式
5.2 String类型的常量池
String s1 = new String("yc");
String s2 = s1.intern();
String s3 = "yc";
System.out.println(s2);//yc
System.out.println(s1 == s2);//false,由于一个是堆内存中的String对象一个是常量池中的String对象,
System.out.println(s3 == s2);//true,由于两个都是常量池中的String对
关于其余内容介绍
01.关于博客汇总连接
02.关于个人博客