JAVA对象实例化过程

Class初始化理解
此篇中详细介绍了JAVA对象的实例化过程

JAVA对象内存分配过程

JVM 这里默认使用HotSpot虚拟机。简单回顾一下JVM内存结构,JVM中主要将使用到的内存划分为五块,其中:

  • 线程私有:虚拟机栈(VM Stack),本地方法栈(Native Method Stack),程序计数器(Program Counter Register)
  • 线程共享:JAVA堆(Heap),方法区(Method Area)

JAVA对象实例化过程中,主要使用到的包括虚拟机栈,JAVA堆和方法区。
JAVA文件经编译之后首先会被加到到JVM方法区,JVM方法区中很重要的一个部分是运行时常量池——用以存储class文件类的版本、字段、方法、接口等描述信息和编译期间的常量和静态变量。
JAVA对象真正进行实例化的地方在JAVA堆和虚拟机栈中,这里无可避免的需要引入指针的概念。

In computer science, a pointer is a programming language object, whose value refers to (or “points to”) another value stored elsewhere in the computer memory using its address. A pointer references a location in memory, and obtaining the value stored at that location is known as dereferencing the pointer. As an analogy, a page number in a book’s index could be considered a pointer to the corresponding page; dereferencing such a pointer would be done by flipping to the page with the given page number. -Wiki

Object A = New Object();在实际内存中,A其实相当于我们给Ojbect这个类的实现起的一个名字,在面向对象编程中,就像狗是属于一类动物,但是特指的那一条狗我们会给他起一个名字用以区分一样。Object用以标记A是属于这个类,而A是特指Object的一个具体实现,而New Object就相当于对这个类创建一个具体实现。所以我们可以了解到,一个对象他首先必须可以指明所属的类,其次它还必须能指明他所特指的哪一个具体实现。
对应的有两种实现方式:
1.句柄访问对象

2.直接指针访问对象

HotSpot采用的是第二种实现方式。
Class的装载包括3个步骤:加载(loading),连接(link),初始化(initialize)
加载
根据上图所示,我们不难理解,当一个对象进行实例化的时候,JVM会根据所需对象类型在JAVA堆中划分内存区,并生成指向方法区对象数据类型的指针用以标识对象。
链接
虚拟机栈中的本地变量表(也有称为局部变量表)中指针指向JAVA堆中划分好的内存区域。JAVA虚拟机采用动态链接方式,只有编译后的class文件并未存储最终方法在内存的表现形式。
初始化
初始化实际上是对class文件中的初始化方法进行调用,其核心还是虚拟机栈中栈帧的一次POP/PUSH。相当于对类中的对象进行一次同样的装载过程。
至此,一个对象完整的实例化过程就全部介绍完毕。

Static 静态化

这块之所以单独摘出,是因为这是经常用到却又容易被忽略的一个地方。
根据 Class初始化理解的实验,我们可以看出实例化并非在程序运行后就立马将所有的静态变量都进行装载。

首先做这样的一个试验

public class StaticObject {//创建静态域,Intalized类构建方法仅用于输出标识信息public static Initalized initalized = new Initalized("Static object is loaded"); //创建静态方法public static void loadTheClass() {System.out.println("Static bject has benn loaded!");}}public class StaticImplement {public static void main(String[] args) {//测试StaticObject类是否执行静态域,静态方法StaticObject impl = null;}}

执行之后,明显没有输出结果。我们知道,在Import或者StaticObject impl = null;这样的声明之后,类实际已经被加载。这说明,类在被加载之后,并不会初始化方法域。

//修改StaticImplement类如下
public class StaticImplement {public static void main(String[] args) {//测试StaticObject类是否执行静态域,静态方法StaticObject impl = null;//执行静态方法impl.loadTheClass();}}

执行结果如下

Static object is loaded
Static bject has benn loaded!

很明显,对象类的静态域和静态方法都被执行了。

JVM回收机制

JAVA与传统语言的最大区别莫过于对于内存的控制。在传统语言当中,我们都是直接控制内存,通过malloc()这种方法申请内存,但无可避免的,在内存使用过程中还涉及到内存的释放,在C中我们熟悉的方式是通过free()进行释放。JAVA程序是运行于JAVA 虚拟机(JVM,Java Virtual Mechine)之上,在初期接触JAVA时,我们似乎没有发现我们需要对内存进行控制,那是因为JVM已经帮助我们完成了JAVA对象的内存的申请与回收。

JAVA对象状态

阅读此节请先阅读上篇,了解对象存在的8种状态。
对象销毁详解
JAVA对象在其生命周期中存在两个属性,可达和终结。
可达分为:可达,终接器-可达,不可达
终结分为:未终结,可终结,已终结
笛卡尔积后,不存在 终接器-可达 且 已终结状态,故共有八种状态。

可达方面,在JVM不断改进过程中,不可达状态被JVM严格防止,因为不可达状态会导致内存泄漏(Memory Leak)。当前使用的JDK一般无法对对象进行内存级的操作,但可以通过Unsafe进行直接的内存操作,详细可以参照:
如何对JAVA进行内存操作 sun.misc.Unsafe类

以下示例展示对象GC过程中能遇到的八种状态

/*** 对象GC状态测设* @author CunChen**/
public class FinalizeEscapeGCTest {public static FinalizeEscapeGCTest test = null;public void isAlive() {System.out.println("alive!");}//在第一次调用的时候被静态变量引用自救@Overrideprotected void finalize() throws Throwable {// Finalizer-Reachable Finlizablesuper.finalize();System.out.println("finalize method executed!");// Reachable FinlizableFinalizeEscapeGCTest.test = this;}public static void main(String[] args) throws InterruptedException {// Reachable Unfinalizedtest = new FinalizeEscapeGCTest();System.out.println("start");// Finalizer-Reachable Unfinlizedtest = null;//第一次成功自救System.gc();//finalize方法优先级低,等待0.5秒Thread.sleep(500);if (test != null) {test.isAlive();} else {System.out.println("Died!");}//第二次自救失败test = null;// Reachable FinalizedSystem.gc();//finalize方法优先级低,等待0.5秒Thread.sleep(500);// Unreachable Finalized if (test != null) {test.isAlive();} else {System.out.println("Died!");}}}

转载于:https://www.cnblogs.com/cunchen/p/9464161.html

【JAVA笔记——道】对象生命周期详解相关推荐

  1. java类的完整生命周期详解

    目录 一.概述 二.过程一:Loading(加载)阶段 1.加载完成的操作 (1)加载的理解 (2)加载完成的操作 2.二进制流的获取方式 3.类模型与Class实例的位置 (1)类模型的位置 (2) ...

  2. 01.软件项目管理与敏捷方法——敏捷项目生命周期详解笔记

    01.软件项目管理与敏捷方法--敏捷项目生命周期详解笔记 00.与其说是船还不如说是熟练的航行技术保证了成功的航行.--George William Curtis 01.敏捷项目是一个按照敏捷宣言宗旨 ...

  3. Spring 生命周期详解

    Spring 生命周期详解 一.传统JAVA bean的生命周期 使用Java关键字 new 进行Bean 的实例化,然后该Bean 就能够使用了. 一旦bean不再被使用,则由Java自动进行垃圾回 ...

  4. Android Activity 生命周期详解及监听

    前言 系列文章: Android Activity 与View 的互动思考 Android Activity 生命周期详解及监听 Android onSaveInstanceState/onResto ...

  5. Fragment生命周期详解

    关于Fragment的生命周期,博主写过Activity与Fragment生命周期详解,基本上把Fragment的生命周期详细介绍过,但是那仅仅是创建一个Fragmnet时的生命周期,而事实上Frag ...

  6. Fragment的懒加载与生命周期详解

    提示:本文仅为笔者学习记录 Fragment的懒加载与生命周期详解 什么是懒加载 了解Fragment的生命周期 onAttach onCreate onCreateView onActivityCr ...

  7. vue 声明周期函数_Vue 生命周期详解

    Vue 生命周期详解 Vue 生命周期流程 最开始,用户使用 new Vue() 创建根 Vue 实例,或者 Vue 实例化子组件都会调用_init方法(我们将这两种实例都称为vm): functio ...

  8. Eclipse中Maven常用命令以及Maven生命周期详解

    Eclipse中maven常用的命令 在某一个maven项目右键快捷方式,然后点击Run As就可以发现几个Maven的命令: Maven Build: 这个命令用于编译Maven工程,执行命令后会在 ...

  9. Cocos Creator 预制体(Prefab) - 生命周期详解

    说明 本文章适用于2.4.x版本的介绍,另外部分逻辑例如start或者enable的调用关系在编辑器或者其他运行环境下可能存在差异,建议大家自行去看源码! 创建 可通过拖拉场景内节点到文件目录上生成一 ...

最新文章

  1. 语义分割--Pixel Deconvolutional Networks
  2. SqlServer性能优化 自定义动化性能收集(四)
  3. 简单的留言板 php,php 简单留言板教程一
  4. brew 镜像_Docker牛刀小试:安装及常用的镜像命令和容器命令
  5. 【Day04】介绍防抖节流原理、区别以及应用,并用 JavaScript 进行实现
  6. 数据库简介(python 版)
  7. mpi tcp连接报错_PHP Swoole长连接常见问题总结
  8. AtomicStampedReference
  9. 转:VC++获取屏幕大小第一篇 像素大小GetSystemMetrics
  10. python中创建类的作用_Python中类的创建与使用详解
  11. McAfee Endpoint Security 10.6卸载
  12. SIP信令交互过程示例
  13. 【数学建模】二手房房价影响因素分析(描述性统计+推断统计综合应用、线性回归预测分析)
  14. 大数据这么火,具体用用到哪些领域?揭秘大数据十三大具体应用场景
  15. 零点定理和罗尔定理的完善?
  16. 从零开始学习信号完整性(SIPI)--2
  17. python中的库有哪些餐厅_推荐一些实用的的 Python 库
  18. MYSQL安装和初始化配置
  19. office word快速排版样式
  20. idea在plugins中搜不到插件MyBatisX

热门文章

  1. 面试官扎心一问:知道 CopyOnWriteArrayList 吗?
  2. spring oauth2+JWT后端自动刷新access_token
  3. 高并发:RocketMQ 削峰实战
  4. Spring集成任务调度功能
  5. 技术人如何做职场沟通?
  6. 高校青椒为避免相亲重复,给没谈成的124个姑娘每人建了个文件夹...
  7. ShakeDrop:深度残差学习中的 ShakeDrop 正则化
  8. 入机器学习大坑,需要什么样的数学水平?
  9. BAT常爱问的面试智力题,你能答对几道?
  10. Excel中将一个表格的数据关联到另一个表格