1、保存到什么地方
①寄存器。这是最快的保存区域,因为它位于和其他所有保存方式不同的地方:处理器内部。然而,寄存器的数量十分有限,所以寄存器是根据需要由编译器分配的。我们对此没有直接的控制权限,也不可能在自己的程序里找到寄存器存在的任何踪迹。
② 堆栈。驻留于常规RAM(随机访问存储器)区域,但可通过它的“堆栈指针”获得处理的直接支持。堆栈指针若向下移,会创建新的内存;若向上移,则会释放哪些内存。这是一种特别快、特别有效的数据保存方式,仅次于寄存器。创建程序时,编译器必须准确的知道堆栈内保存的所有数据的“长度”以及“存在时间”。这是由于他必须生成相应的代码,以便向上和向下移动指针。这一限制无疑影响了程序的灵活性,所以尽管有些java数据保存在堆栈里--特别是对象句柄,但对象并不放到其中。
③ 堆。一种常规用途的内存池(也在RAM区域),其中保存了对象。和堆栈不同,“内存堆”或“堆”(heap)最吸引人的地方在于编译器不必知道要从堆里分配多少存储空间,也不必知道存储的数据要在堆里停留多长时间。因此用堆保存数据时会得到更大的灵活性。要求创建一个对象时,只需要用new命令编制相关的代码即可。执行这些代码时,会在堆里自动进行数据的保存。当然,为达到这种灵活性,必然会付出一定的代价:在堆里分配存储空间需要花费更长的时间!
④静态存储。这儿的“静态(static)”是指“位于固定位置”(尽管也在RAM里)。程序运行期间,静态存储的数据将随时等候调用。可用static关键字之处一个对象的特定元素是静态的。但对象本身永远都不会置入静态存储空间。
⑤常量存储。常数值通常直接置于程序代码的内部。这样做是安全的,因为它们永远都不会改变。有的常数需要严格的保护,所以可以考虑将他们置入只读存储器(ROM)。
⑥非RAM存储。若数据完全独立于一个程序之外,则程序不运行时仍可存在,并在程序的控制范围之外。其中两个最主要的例子便是“流式对象”和“固定对象”。对于流式对象,对象会变成字节流,通常会发给另一台机器。而对于固定对象,对象保存在磁盘中。即使程序中止运行,他们仍然保持自己的状态不变。对于这些类型的数据存储,一个特别有用的技巧就是他们能存在于其他媒体中。一旦需要,甚至能将他们恢复成普通的、基于RAM的对象。
2、类成员变量初始化
①一个对象在创建时,或者类的static方法/static字段首次访问时,解析器必须找到该类(在事先设好的类路径里搜索)
②找到类后,加载器加载该类,并去静态存存储区检索该类的static字段和static初始化块。如果该类已经加载过,则这部分跳过不在执行;如果该类尚未加载过,则首先为static字段赋初值,然后执行static初始化块操作。如果子类和父类都有static成员变量和static静态初始化块,则首先为父类的static字段赋初值、然后执行父类的static静态初始化块,在为子类的static字段赋初值,在执行子类的static静态初始化块。因此无论创建多少个对象,static字段和static初始化块,只会在第一次类加载的过程中执行。(注意这部分是在类加载的过程中执行)。
③然后创建该类的一个实例化对象,该类的对象的构造进程首先会在内存堆(heap)里为该对象分配足够多的存储空间。
④这种存储空间会清为零,为对象中的所有基本类型设为他们的默认值。
⑤进行字段定义时发生的所有初始化都会执行。这里主要包括两部分:一个是字段赋初值;一个是初始化块进行初始化;具体的执行顺序与构造器也有一定的关系。
⑥执行构造器。一般来说构造器会最后执行,但是如果存在继承的情况,那么父类的构造器会优先于子类的初始化(变量赋初值和初始化块),但是晚于父类自己的初始化过程。具体的执行过程是父类的成员变量赋初值、父类的初始化块、父类的构造函数、子类变量赋初值、子类初始化块、子类构造函数。
总结:因此综上所述,累的初始化过程如下
3、内存和其他资源的回收
在讲这一部分,那就不得不提三部分知识要点,分别是:类提供的finalize()方法的作用,System.gc()的作用,以及垃圾回收器的工作原理。通过这些,我们需要做一下延伸扩展,知道jvm堆大小的调整。
java可用垃圾回收器回收不再使用的对象占据的内存,用完后简单的释放一个对象并非总是安全的。假如对象分配一个“特殊”内存区域,没有使用new。垃圾回收器就不知道如何释放这个特殊内存区域。因为垃圾回收器只知道有new分配的内存,不知道如何释放这些特殊的内存。为了解决这个问题,java提供了一个名为finalize()的方法,在理想情况下,他的工作原理应该是这样的:一旦垃圾回收器准备好释放对象占用的存储空间,他首先调用finalize(),而且只有在下一次垃圾回收过程中,才会真正回收对象的内存。所以如果使用finalize(),就可以在垃圾收集期间进行一些重要的清除或清扫工作。牢记finalize不等同于C++的的destructor;我们的对象可能不会当做垃圾被收掉。垃圾回收器只与内存有关,而finalize就是用来处理一些特殊的内存或者其他资源的回收,而且finalize只在垃圾回收器准备回收资源的时候执行。
System.gc()是通知垃圾回收器应该进行垃圾回收了,但是jvm并不一定去真的回收。该方法只是通知jvm,jvm到底做不做由它自身说了算。JVM垃圾回收只有在内存到达影响JVM后续工作的时候,他才会去执行垃圾回收操作。Runtime.getRuntime().gc()与System.gc()功能相同。
JVM的垃圾回收器的目的在于清理不在使用的对象。gc通过确定对象是否被活动的对象应用来确定是否收集该对象。常用的方法是引用计数和对象引用遍历。
引用计数算法使用引用计数器来区分存活对象和不再使用的对象。一般来说,堆中的每个对象对应一个引用计数器。当每一次创建一个对象并赋给一个变量时,引用计数器置为1。当对象被赋给任意变量时,引用计数器每次加1当对象出了作用域后(该对象丢弃不再使用),引用计数器减1,一旦引用计数器为0,对象就满足了垃圾收集的条件。
对象引用遍历从根集(所谓根集就量正在执行的Java程序可以访问的引用变量的集合包括局部变量、参数、类变量,程序可以使用引用变量访问对象的属性和调用对象的方法)开始,沿着整个根集对象图上的每条链接,递归确定可到达(reachable)的对象。如果某对象不能从这些根对象的一个(至少一个)到达,则将它作为垃圾收集。在对象遍历阶段,gc必须记住哪些对象可以到达,以便删除不可到达的对象,这称为标记(marking)对象。下一步,gc要删除不可到达的对象。删除时,有些gc只是简单的扫描堆栈,删除未标记的未标记的对象,并释放它们的内存以生成新的对象,这叫做清除(sweeping)。这种方法的问题在于内存会分成好多小段,而它们不足以用于新的对象,但是组合起来却很大。因此,许多gc可以重新组织内存中的对象,并进行压缩(compact),形成可利用的空间。
JVM堆大小的调整。sun hotspot使用分代收集器,把堆分成三个主要的域:新域、旧域以及永久域。JVM生成的所有新对象放在新域中。一旦 对象经历了一定数量的垃圾收集循环后,便获得使用期并进入旧域。在永久域中存储class和method对象。就配置而言,永久域是一个独立域并且不认为是堆的一部分。
下面介绍如何控制这些域的大小:可使用-Xms和-Xmx控制整个堆的原始大小或最大值。使用-XX:NewRation设置新域和旧域的比列。-XX:NewSize和-XX:MaxNewSize设置新域在堆中的初始值和最大值。-Xmn设置新域的最大最小值为同一个数值。-XX:PerSize标志设置永久域的初始值。-XX:MaxPerSize标志永久域最大值。
相关推荐
Java的初始化包括类的加载、连接和初始化三个过程,而清理则主要指垃圾回收机制。 首先,Java初始化的主要特性表现在类的加载过程上。与其他一些传统编程语言(如C++)不同,Java的类并不是在程序启动时立即加载的...
- 基本类型的变量存储在栈内存中,而引用类型的变量存储在堆内存中,它们指向的对象实例在堆中创建。 - 当一个变量的生命周期结束时,对应的内存空间会被回收。 深入理解Java变量的这些概念对编写高效、健壮的...
- 存储位置:成员变量和类变量存储在堆内存中,而局部变量存储在栈内存中。 - 生命周期:成员变量和类变量的生命周期与对象或类的生命周期相关,局部变量的生命周期与方法调用相关。 - 访问权限:成员变量和类变量...
这些变量的生命周期与对象相同,当对象被创建时初始化,当对象被垃圾回收时,它们也随之消失。可以通过对象名来访问实例变量,如`sd1.i`或`sd2.i`。此外,可以使用`this`关键字来引用当前对象的实例变量,虽然在...
在这个文档“java变量的五种方式t共2页.pdf.zip”中,我们预计会涵盖Java中的五种主要的变量类型及其用法。尽管实际内容无法在当前环境中直接查看,但根据常规的Java教程,我可以提供一个详细的概述。 1. **基本...
Java变量类型是编程基础,也是面试中经常被问到的话题。理解这些概念对于任何Java开发者都至关重要。在Java中,变量分为两类:基本数据类型(Primitive Data Types)和引用数据类型(Reference Data Types)。 一、...
在Java中,当我们使用`new`关键字创建一个对象时,实际上是向内存(通常是堆)申请空间,并执行类的构造方法来初始化对象的成员变量。例如,`A a1 = new A();` 这行代码创建了一个A类的实例,`new A()`是对象,而`a1...
数组初始化时,Java会为数组的所有元素分配内存,并根据初始化列表为每个元素赋予初始值。对于未初始化的数组,如`int[] b = new int[5];`,虽然在堆上分配了足够的空间,但元素的初始值默认为该类型的默认值(如int...
这可能是指文件内容详细阐述了这些概念之间的差异,如成员变量和局部变量的生命周期、作用域、初始化时间以及静态变量与实例变量的共享特性,以及成员方法和静态方法的调用方式等。 理解这些基本概念对于编写有效...
在Java中,一个类可能包含静态变量、静态初始化块、成员变量、实例初始化块和构造函数。当创建一个对象时,这些元素的加载顺序遵循特定的规则: 1. 静态成员和静态初始化块:在任何实例被创建之前,首先是父类的...
Java中的变量是编程中最基础的概念,它用于...在编程实践中,应遵循良好的变量命名规范,合理控制变量的作用域,注意变量的初始化和生存期,以及理解不同类型变量在内存中的存储方式,以便更好地利用Java虚拟机的特性。
1. **对象创建**:当程序执行到new关键字时,会在堆内存中为新对象分配空间,并初始化其成员变量。 2. **对象使用**:对象创建后,在程序中被使用,如调用其方法或读写其成员变量等。 3. **对象回收**:当对象不再被...
存在没有变量的对象,如字符串,也存在没有对象的变量,如尚未初始化的变量。 类变量的有效期是从类的创建开始到类消失为止,而一般情况下,除非程序中止,否则类不会消失的。成员变量的有效期是从对象生成起。局部...
- **5.2.3 默认初始化值**:实体中的变量会自动初始化为默认值,如数值类型为0,引用类型为null。 - **5.2.4 垃圾回收**:不再使用的实体最终会被垃圾回收器在某个不确定的时间点回收,以释放内存空间。 以上内容...
总之,Java对象的创建涉及内存分配和初始化,而垃圾回收则是Java内存管理的关键机制,通过自动回收不再使用的对象,确保程序高效、稳定地运行。理解这些概念对于Java开发者来说至关重要,有助于编写出更高质量的代码...
未初始化的引用变量则无法指向任何对象,如果试图使用会导致编译错误或运行时异常。 变量的有效期与其所指对象的生存期是两个不同的概念。变量的有效期取决于其类型和声明的位置。类变量(静态变量)从类加载时存在...
总的来说,使用静态成员变量来计算Java程序中实例化的对象数量是一种实用的技术,可以帮助开发者更好地理解他们的代码是如何消耗内存的。然而,对于更复杂的内存分析,可能需要依赖于Java虚拟机(JVM)提供的工具,...
如果只声明不赋值,那么在使用变量之前必须为其赋值,否则编译器会报错提示变量未初始化。例如: ```java int age; // 声明一个变量age,但未赋值 int age = 19, age2 = 90; // 声明并赋值两个变量age和age2 ``` ...
基本类型的变量直接存储数据值,而引用类型的变量存储的是指向数据对象的引用。在方法中传递变量时,如果是基本类型,是按值传递的,即传递的是值的副本;如果是引用类型,则是按引用传递,即传递的是引用的副本,但...