Java的内存机制详解

 更新时间:2017年03月17日 11:50:23   作者:·水龙吟·  
本文主要介绍了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.全局代码区:保存所有的方法定义。

以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,同时也希望多多支持脚本之家!

相关文章

  • Java深入讲解Object类常用方法的使用

    Java深入讲解Object类常用方法的使用

    前面java继承中说到的Object类是java中一个特殊的类,所有的类都是直接或者间接的继承自Object类,即如果某个类没有使用extends关键字则默认是java.lang.Object类的子类,所以所有的类都可以使用Object类中定义的方法,下面介绍Object类的常用方法
    2022-04-04
  • JavaEE SpringMyBatis是什么? 它和Hibernate的区别及如何配置MyBatis

    JavaEE SpringMyBatis是什么? 它和Hibernate的区别及如何配置MyBatis

    这篇文章主要介绍了JavaEE Spring MyBatis是什么? 它和Hibernate的区别有哪些?如何配置MyBatis?本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-08-08
  • Java数组常见应用详解【创建、遍历、排序、查找】

    Java数组常见应用详解【创建、遍历、排序、查找】

    这篇文章主要介绍了Java数组常见应用,结合实例形式详细分析了java数组的基本定义、创建、遍历、排序、查找等相关操作技巧与使用注意事项,需要的朋友可以参考下
    2020-02-02
  • java swing标准对话框具体实现

    java swing标准对话框具体实现

    这篇文章介绍了swing标准对话框的具体实现方法,有需要的朋友可以参考一下
    2013-06-06
  • 解决response.setHeader设置下载文件名无效的问题

    解决response.setHeader设置下载文件名无效的问题

    这篇文章主要介绍了解决response.setHeader设置下载文件名无效的问题,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-01-01
  • Java输出链表倒数第k个节点

    Java输出链表倒数第k个节点

    这篇文章主要介绍了Java输出链表倒数第k个节点的相关内容,涉及三种设计思路及代码示例,具有一定参考价值,需要的朋友可以了解下。
    2017-10-10
  • Java案例分享-集合嵌套

    Java案例分享-集合嵌套

    这篇文章主要介绍了Java案例分享-集合嵌套,通过案例创建一个ArrayList集合,存储三个元素,每一个元素都是HashMap,每一个HashMap的键和值都是String,并遍历,实际操作内容需要的小伙伴可以参考一下
    2022-04-04
  • Java中冒泡排序的原生实现方法(正序与逆序)

    Java中冒泡排序的原生实现方法(正序与逆序)

    这篇文章主要给大家介绍了关于Java中冒泡排序的原生实现方法(正序与逆序)的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-11-11
  • 浅谈Spring Boot Web 应用性能优化

    浅谈Spring Boot Web 应用性能优化

    这篇文章主要介绍了浅谈Spring Boot Web 应用性能优化,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2018-07-07
  • Java CompletableFuture使用方式

    Java CompletableFuture使用方式

    这篇文章主要介绍了Java CompletableFuture使用方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2024-07-07

最新评论