「轉」Java的内存机制

0.参考资料:

http://www.j2megame.org/index.php/content/view/2246/125.html

1.Java的内存机制

 Java 把内存划分成两种:一种是栈内存,另一种是堆内存。在函数中定义的一些基本类型的变量对象的引用变量都是在函数的栈内存中分配,当在一段代码块定义一个变量时,Java 就在栈中为这个变量分配内存空间,当超过变量的作用域比如,在函数A中调用函数B,在函数B中定义变量a,变量a的作用域只是函数B,在函数B运行完以后,变量a会自动被销毁。分配给它的内存会被回收,Java 会自动释放掉为该变量分配的内存空间,该内存空间可以立即被另作它用。

  堆内存用来存放由 new 创建的对象和数组,在堆中分配的内存,由 Java 虚拟机的自动垃圾回收器来管理。在堆中产生了一个数组或者对象之后,还可以在栈中定义一个特殊的变量,让栈中的这个变量的取值等于数组或对象在堆内存中的首地址,栈中的这个变量就成了数组或对象的引用变量,以后就可以在程序中使用栈中的引用变量来访问堆中的数组或者对象,引用变量就相当于是为数组或者对象起的一个名称。引用变量是普通的变量,定义时在栈中分配,引用变量在程序运行到其作用域之外后被释放。而数组和对象本身在堆中分配,即使程序运行到使用 new 产生数组或者对象的语句所在的代码块之外,数组和对象本身占据的内存不会被释放,数组和对象在没有引用变量指向它的时候,才变为垃圾,不能在被使用,但仍然占据内存空间不放,在随后的一个不确定的时间被垃圾回收器收走(释放掉)。这也是 Java 比较占内存的原因,实际上,栈中的变量指向堆内存中的变量,这就是 Java 中的指针!

代码实例Test01:单个对象创建

class Person{
    String name;
    int age;
    public void tell(){
        System.out.println("姓名:"+name+"年龄"+age);
    }
}

public class Test01 {
    public static void main(String[] args) {
        Person per=new Person();
    }
}

在上述程序中实例化了一个对象per,在实例化对象的过程中需要在内存中开辟空间,这其中就包括栈内存和对内存。具体的内存分配如下图所示:

我们可以从上图中发现,对象名称per被保存在了栈内存中(更加准确的说法是,在栈内存中保存的是堆内存空间的访问地址),而对象的具体内容,比如属性name和age,被保存在了堆内存中。因为per对象只是被实例化,还没有具体被赋值,所以都是默认值。字符串的默认值为null,int类型的默认值为0。前面也已经提到,堆内存空间必须使用new关键字才能开辟。

代码实例Test02:多个对象创建

class Person{
    String name;
    int age;
    public void tell(){
        System.out.println("姓名:"+name+",年龄:"+age);
    }
}

public class Test02 {
    public static void main(String[] args) {
        Person per1=new Person();
        Person per2=new Person();

        per1.name="张三";
        per1.age=30;
        per2.name="李四";
        per2.age=33;

        per1.tell();
        per2.tell();
    }
}

关键概念:类跟数组一样,都是属于引用类型,引用类型就是指一堆对内存可以同时被多个栈内存指向。下面来看一下引用传递的简单实例。

代码实例Test03:对象引用传递1

class Person{
    String name;
    int age;
    public void tell(){
        System.out.println("姓名:"+name+",年龄:"+age);
    }
}

public class Test03{
    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();
    }
}

程序运行结果为:

姓名:张三,年龄:33
姓名:张三,年龄:33

从程序的运行结果可以发现,两个对象输出的内容一样,实际上所谓的引用传递,就是将一个堆内存空间的使用权交个多个栈内存空间,每个栈内存空间都可以修改堆内存空间的内容,此程序的内存分配图如下所示:

注意:上述实例中对象per2没有堆内存空间,这是因为对象per2只进行了声明操作,也没有进行实例化操作。只有使用new关键字实例化以后才会有对内存空间。

代码实例Test04:对象引用传递2

class Person{
    String name;
    int age;
    public void tell(){
        System.out.println("姓名:"+name+",年龄:"+age);
    }
}

public class Test04 {
    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();
    }
}

上述程序运行结果为:

姓名:张三,年龄:30
姓名:张三,年龄:30

从程序的输出结果可以发现可Test03一样。不过内存分配发生了一些变化,具体如下所示:

注意点:

  1. Java本身提供垃圾收集机制(Garbage Collection,GC),会不定期施放不用的内存空间,只要对象不用了,就会等待GC释放空间,如上面堆内存中的name="李四";age=33。
  2. 一个栈内存只能指向一个对内存空间,如果要想再指向其他的堆内存空间,则必须先断开已有的指向才能分配新的指向。

java中常用的内存区域

在java中主要存在4块内存空间,这些内存的名称及作用如下:

  1. 栈内存空间:保存所有的对象名称(更准确地说是保存了引用的堆内存空间的地址)
  2. 堆内存空间:保存每个对象的具体属性内容。
  3. 全局数据区:保存static类型的属性。
  4. 全局代码区:保存所有的方法定义。
时间: 2024-10-05 19:13:32

「轉」Java的内存机制的相关文章

Java的内存机制(转)

0.参考资料: http://www.j2megame.org/index.php/content/view/2246/125.html  转自 http://www.cnblogs.com/xwdreamer/archive/2012/04/01/2428857.html 1.Java的内存机制 Java 把内存划分成两种:一种是栈内存,另一种是堆内存.在函数中定义的一些基本类型的变量和对象的引用变量都是在函数的栈内存中分配,当在一段代码块定义一个变量时,Java 就在栈中为这个变量分配内存空

Java的内存机制

Java 把内存划分成两种:一种是栈内存,另一种是堆内存.在函数中定义的一些基本类型的变量和对象的引用变量都是在函数的栈内存中分配,当在一段代码块定义一个变量时,Java 就在栈中为这个变量分配内存空间,当超过变量的作用域后(比如,在函数A中调用函数B,在函数B中定义变量a,变量a的作用域只是函数B,在函数B运行完以后,变量a会自动被销毁.分配给它的内存会被回收),Java 会自动释放掉为该变量分配的内存空间,该内存空间可以立即被另作它用. 堆内存用来存放由 new 创建的对象和数组,在堆中分配

如何「偷」Android 的内存?

之前在做一个内存优化的时候,使用到了MemoryFile,由此发现了MemoryFile的一些特性以及一个非常trickly的使用方法,因此在这里记录一下 What is it MemoryFile是android在最开始就引入的一套框架,其内部实际上是封装了android特有的内存共享机制Ashmem匿名共享内存,简单来说,Ashmem在Android内核中是被注册成一个特殊的字符设备,Ashmem驱动通过在内核的一个自定义slab缓冲区中初始化一段内存区域,然后通过mmap把申请的内存映射到

[java基础] java 虚拟机内存机制

了解java虚拟器内存机制的好处 当我们需要解决一些棘手的问题,比如性能优化,解决OOM异常时,如果我们了解java虚拟机的内存机制,就知道从哪里下手处理这些问题了 如何了解 我从三方面去说明他 进程级别 我们在pc上做一个应用,在手机上做一个app,都是以进程的级别存在的.在进程这个级别中,内存被分配给/分配为 java堆.方法区(含有常量存储区).各个线程 java堆:java堆是GC线程回收内存的区域,他主要是用来存储各种对象 方法区:方法区存储了class在加载之后的信息,如全局变量,方

「3」Java开发环境搭建

1.JRE和JDK的概念 ●什么是JRE和JDK? ●JRE(Java Runtime Environment-Java运行环境).所有的Java程序都要在JRE下才能运行.它包括了JVM(Java Virtual Machine)和JAVA核心类库等. ●JDK(Java Development Kit-Java开发工具包).它是整个Java的核心.包括了Java运行环境.Java开发工具(javac.java.javadoc等)和Java基础类库. 总结:与JDK相比,JRE它不包含开发工具

「Nosql」Redis小记-内存解析&内存消耗篇

*博客搬家:初版发布于 2017/08/12 18:32    原博客地址:https://my.oschina.net/sunqinwen/blog/1507171 Redis内存消耗分析 注:本文默认读者已初步学会使用redis了. 首先我们通过info命令查看相关指标,其中几个memory的重要指标整理出来如下: 属性 解释 used_memory redis内部存储的所有数据的内存总占用量(自身内存+对象内存+缓冲内存) used_memory_ress redis进程占用的总物理内存

java内存机制

原文:http://www.cnblogs.com/xwdreamer/archive/2012/04/01/2428857.html 1.Java的内存机制 Java 把内存划分成两种:一种是栈内存,另一种是堆内存.在函数中定义的一些基本类型的变量和对象的引用变量都是在函数的栈内存中分配,当在一段代码块定义一个变量时,Java 就在栈中为这个变量分配内存空间,当超过变量的作用域后(比如,在函数A中调用函数B,在函数B中定义变量a,变量a的作用域只是函数B,在函数B运行完以后,变量a会自动被销毁

Java的内存存储

0.参考资料: http://www.j2megame.org/index.php/content/view/2246/125.html 1.Java的内存机制 Java 把内存划分成两种:一种是栈内存,另一种是堆内存.在函数中定义的一些基本类型的变量和对象的引用变量都是在函数的栈内存中分配,当在一段代码块定义一个变量时,Java 就在栈中为这个变量分配内存空间,当超过变量的作用域后(比如,在函数A中调用函数B,在函数B中定义变量a,变量a的作用域只是函数B,在函数B运行完以后,变量a会自动被销

Java的参数传递是「按值传递」还是「按引用传递」?

Java 编程语言中最大的困惑之一就是: java 是按值传递还是按引用传递.我在面试中经常会问面试者这个问题,但还是有很多面试者对这个问题的理解不是很正确. 有很多面试者是这样理解的: 如果传递类型为基础数据类型,则按值传递, 如果传递类型为类,则按引用传递. 这样的理解正确吗?他们甚至还可以写出示例代码来验证他们的想法,让我们来一起看一看大多数人是如何验证"基础类型按值传递,非基础类型按引用传递"这个想法的: 基础类型数据作为参数传递 /** * 基础类型数据作为参数传递 * @A