这里有新鲜出炉的 Java 并发编程示例,程序狗速度看过来!
java 是一种可以撰写跨平台应用软件的面向对象的程序设计语言,是由 Sun Microsystems 公司于 1995 年 5 月推出的 Java 程序设计语言和 Java 平台(即 JavaEE(j2ee), JavaME(j2me), JavaSE(j2se))的总称。
本文主要介绍了 Java 的内存机制的相关知识,具有很好的参考价值,下面跟着小编一起来看下吧
Java 把内存分为两种:一种是栈内存,另一种是堆内存。在函数中定义的一些基本类型的变量和对象的引用变量都是在函数的栈内存中分配,当在一段代码块定义一个变量时,Java 就在栈中为这个变量分配内存空间, 当超过变量的作用域后 (比如,在函数 A 中调用函数 B,在函数 B 中定义变量 a,变量 a 的作用域只是函数 B,在函数 B 运行以后,变量 a 会自动被销毁。分配给它的内存会被回收),Java 会自动释放掉为该变量分配的内存空间,该内存空间可以立即另做他用。
堆内存用来存放由 new 创建的内存数组,在堆中分配的内存,由 Java 虚拟机的自动垃圾回收器来管理。在堆中产生一个数组或对象之后,还可以在栈中定义一个特殊的变量,让栈中的这个变量的取值等于数组或对象在堆内存中的首地址,栈中的这个变量就变成了数组或对象的引用变量,以后就可以在程序中使用栈中的变量来访问堆中的数组或者对象,引用变量就相当于为数组或者对象起的一个名字。引用变量是普通的变量,定义时在栈中分配,引用变量在程序运行到其他作用域之外后边释放。而数组和对象本省在堆中分配,即使程序运行到使用 new 产生的数组或者对象的语句所在的代码块之外,数组和对象本省占据的内存不会被释放。数组和对象在没有引用变量指向它的时候,才变为垃圾,不能再被使用,在随后的一个不确定时间被垃圾回收器收走(释放掉)。这也是 Java 比较占内存的原因,实际上,栈中的变量指向堆内存中的变量,这就是 Java 中的指针。
代码实例 Demo1: 单个对象创建
- class Person {
- String name;
- int age;
- public void tell() {
- System.out.println("姓名:" + name + ",年龄:" + age);
- }
- }
- public class Demo1 {
- public static void main(String[] args) {
- Person per = new Person();
- }
- }
在上述程序中实例化了一个对象 per,在实例化的过程中需要再内存中开辟空间,这其中就包括栈内存和堆内存,具体的内存分配如下图所示:
图 1-1 对象的实例化过程
我们可以从上图中发现,对象名称 per 被保存在了栈内存中 (更加准确的说法是,在栈内存中保存的是堆内存空间的访问地址), 而对象的具体内容,比如属性 name 和 age,被保存在堆内存中。因为 per 对象只是被实例化,还没有被具体赋值,所以都是默认值。字符串的默认值为 null,int 的类型的默认值为 0。前面已经提到,堆内存空间必须使用 new 关键字才能开辟。
代码实例 Demo2: 多个对象创建
- class Person {
- String name;
- int age;
- public void tell() {
- System.out.println("姓名:" + name + ",年龄:" + age);
- }
- }
- public class Demo2 {
- public static void main(String[] args) {
- Person per1 = new Person();
- Person per2 = new Person();
- per1.name = "张三";
- per1.age = 30;
- per2.age = 33;
- per1.tell();
- per2.tell();
- }
- }
图 1-2 实例化两个对象
关键概念: 类跟数组一样,都是属于引用类型,引用类型就是指同一个堆内存可以被多个栈内存指向,下面来看一下引用传递的简单实例。
代码实例 Demo3: 对象引用传递 1
- class Person {
- String name;
- int age;
- public void tell() {
- System.out.println("姓名:" + name + ",年龄:" + age);
- }
- }
- public class Demo3 {
- public static void main(String[] args) {
- Person per1 = new Person();
- Person per2 = per1; //-------注意--------
- per1.name = "张三";
- per1.age = 30;
- per2.age = 33;
- per1.tell();
- per2.tell();
- }
- }
程序运行结果为:
从程序的运行结果可以发现,两个对象输出的内容一样,实际上所谓的引用传递,就是将一个堆内存空间的使用权交给多个栈内存空间,每个栈内存空间都可以修改堆内存空间的内容,此程序的内存分配图如下所示:
图 1-3 对象引用的传递内存分配
图 1-3 对象引用的传递内存分配 (续)
注意: 上述实例中对象 per2 没有堆内存空间,这是因为对象 per2 只进行声明操作,也没有进行实例化操作。只是使用 new 关键字,实例化以后才会有堆内存空间
代码实例 Demo4: 对象引用传递 2
- class Person {
- String name;
- int age;
- public void tell() {
- System.out.println("姓名:" + name + ",年龄:" + age);
- }
- }
- public class Demo4 {
- public static void main(String[] args) {
- Person per1 = new Person();
- Person per2 = new Person();
- per1.name = "张三";
- per1.age = 30;
- per2.name = "李四";
- per2.age = 33;
- per2 = per1; //-----注意----
- per1.tell();
- per2.tell();
- }
- }
上述运行程序结果为:
从程序的输出结果可以发现跟 Demo3 差不多。不过内存分配发生了一些变化,具体如下所示:
图 1-4 (垃圾对象) 的产生
注意点:
1.Java 本身提供垃圾收集机制 (Garbage Collection,GC), 会不定期释放不用的内存空间,只要对象不用了,就会等待 GC 释放空间,如上面堆内存中的 name="李四";age=33。
2. 一个栈内存只能指向一个堆内存空间,如果要想指向其他堆内存空间,则必须先断开已有的指向,才能分配新的指向。
Java 中常见的内存区域
在 Java 中主要存在 4 块内存空间,这些内存的名称及作用如下:
1. 栈内存空间: 保存所有对象的名称。
2. 堆内存空间: 保存每个对象的具体属性内容。
3. 全局数据区: 保存 static 类型的属性值。
4. 全局代码区: 保存所有的方法定义。
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,同时也希望多多支持 PHPERZ!
来源: http://www.phperz.com/article/17/1218/357941.html