zoukankan      html  css  js  c++  java
  • 论 Java 中的内存分配

    -------------------------------------------------------------------------

    Java内存分配主要包括以下几个区域:

    1. 寄存器:我们在程序中无法控制

    2. :存放基本类型的数据和对象的引用,但对象本身不存放在栈中,而是存放在堆中

    3. :存放用new产生的数据

    4. 静态域:存放在对象中用static定义的静态成员

    5. 常量池:存放常量

    6. 非RAM(随机存取存储器)存储:硬盘等永久存储空间

     ------------------------------------------------------------------------------------

    一. 寄存器(Registers):

         这是速度最快的存储场所,因为寄存器位于处理器内部,这一点和其他的存储媒介都不一样。不过寄存器个数是有限的。

        在内存中的寄存器区域是由编译器根据需要来分配的。我们程序开发人员不能够通过代码来控制这个寄存器的分配。

        所以说,这第一个存储区域寄存器,我们只能够看看,而不能够对其产生任何的影响。,也没办法在程序里头感觉到寄存器的任何存在迹象。

        JVM只设置了4个最为常用的寄存器。
      pc程序计数器
      optop操作数栈顶指针
      frame当前执行环境指针
      vars指向当前执行环境中第一个局部变量的指针
      所有寄存器均为32位。
      pc用于记录程序的执行。optop,frame和vars用于记录指向Java栈区的指针。

    二. 栈(Stack):

     又称堆栈

       位于一般的RAM中。处理器经由指针提供直接支持。

       当程序配置一块新的内存时,stack指针便往后移;释放内存时,指针则往前移。

       这种方式不仅很快,效率也高,速度仅次于寄存器。

       用于存放对象引用以及基本的数据类型对象,不能用于存储Java对象本身。


    三. Heap):
       一种通用的内存空间,用来存放Java对象。

       Heap不同于stack之处在于,编译器不需知道究竟得从heap中配置多少空间,也不需知道从heap上配置的空间究竟需要存在多久。

       因此,自heap配置存储空间可以获得高度的弹性。每当你需要产生对象,只需在程序中使用new,那么执行的时候,便会自heap配置空间。

       当然,你得为这样的弹性付出代价:从heap配置空间,比从stack配置,所耗费的时间多了不少。

     单论内存空间中的堆和栈:

       1.栈(stack)与堆(heap)都是Java用来在Ram中存放数据的地方。Java自动管理栈和堆,程序员不能直接地设置栈或堆。

       2.优缺点:

          栈:

      栈的优势是,存取速度比堆要快,仅次于直接位于CPU中的寄存器

      但缺点是,存在栈中的数据大小与生存期必须是确定的,缺乏灵活性。另外,栈数据在多个线程或者多个栈之间是不可以共享的,但是在栈内部多个值相等的变量是可以指向一个地址的

          堆:

      堆的优势是可以动态地分配内存大小,生存期也不必事先告诉编译器,Java的垃圾收集器会自动收走这些不再使用的数据。

      但缺点是,由于要在运行时动态分配内存,存取速度较慢。

       3.栈有一个很重要的特殊性,就是存在栈中的数据可以共享

    四. 静态域:

        静态存储区域就是指在固定的位置存放应用程序运行时一直存在的数据,Java在内存中专门划分了一个静态存储区域来管理一些特殊的数据变量如静态的数据变量,需要明确的一点就是,Java对象是不保存在这个地方的,而只是把对象中的一些特殊元素放置这。

        类变量也叫静态变量,也就是在变量前加了static 的变量;
        实例变量也叫对象变量,即没加static 的变量;
      区别在于:
         类变量和实例变量的区别在于:类变量是所有对象共有,其中一个对象将它值改变,其他对象得到的就是改变后的结果;而实例变量则属对象私有,某一个对象将其值改变,不影响其他对象;

      特点:

          这儿的“静态”(Static)是指“位于固定位置”(尽管也在RAM里)。程序运行期间,静态存储的数据将随时等候调用。可用static关键字指出一个对象的特定元素是静态的。但Java对象本身永远都不会置入静态存储空间
        例:

    public class A{
        static int a = 0; //类变量
        private int b = 0; //实例变量
    }
    
    public class B{
        public void main (String[] args){
            A a1 = new A();
            A a2 = new A();
            a1.a = 3; // 等同于 A.a = 3;
            a1.b = 4 ;
            System.out.println(a2.a); //结果为3
            //类变量是针对所有对象的,所以a1改变a,a2的a也改变
            System.out.println(a2.b); //结果为0
            //实例只改变自身的,所以a1对象的b改变,不影响对象a2的b变量
        }
    } 

       

    五. 常量池:

      常量池在java用于保存在编译期已确定的,已编译的class文件中的一份数据。它包括了关于类,方法,接口等中的常量,也包括字符串常量,如String s = "java"这种申明方式;当然也可扩充,执行器产生的常量也会放入常量池,故认为常量池是JVM的一块特殊的内存空间。

      背景:

        在Java对象中还有一类特殊的元素,我们叫做常量。由于常量的值是稳定不变的,如圆周率。为此把他们放在代码的内部是可行的。

        不过有些时候,在进行一些嵌入式系统开发的时候,我们往往不这么做。而是会把常量元素跟代码分开来保存。

        如我们会根据情况把常量的值存放在一些只读存储器中。这主要是为了一些特殊的功能考虑的。

        如出于版权控制的需要。如在打印机上为了保护原装耗材的版权,往往把常量跟代码分开存放

    特点:

        在Java程序中,有很多的东西是永恒的,不会在运行过程中变化。

              比如一个类的名字,一个类字段的名字/所属类型,一个类方法的名字/返回类型/参数名与所属类型,一个常量,还有在程序中出现的大量的字面值。

       常数值通常直接置于程序代码内部。这样做是安全的,因为它们永远都不会改变。有的常数需要严格地保护,所以可考虑将它们置入只读存储器(ROM)。

    六.  非RAM存储:

      若数据完全独立于一个程序之外,则程序不运行时仍可存在,并在程序的控制范围之外。其中两个最主要的例子便是“流式对象”和“固定对象”。对于流式对象,对象会变成字节流,通常会发给另一台机器。而对于固定对象,对象保存在磁盘中。

      即使程序中止运行,它们仍可保持自己的状态不变。对于这些类型的数据存储,一个特别有用的技巧就是它们能存在于其他媒体中。一旦需要,甚至能将它们恢复成普通的、基于RAM的对象

       背景:  

      有时候,有些程序运行所需要的数据我们还会放置在其他地方。如在一些系统中需要用到流对象,这个对象的数据并没有保存在上面所谈到的任何一个存储区域,这个对象直接被转为为字节流,发送到其他的主机上去了。另外有一种叫做持久化的对象,其是被存储在硬盘中的

    七. 论各类型内存的执行速度:

      寄存器 > 堆栈 > 堆 > 其他

    (C) 房上的猫 。 保留所有权利。
     https://www.cnblogs.com/lsy131479/

    如需转载,请注明出处!!!

  • 相关阅读:
    20160205
    20151120
    20151023
    20151023
    20140207
    yum工具介绍
    Linux程序包管理
    Linux任务计划、周期性任务执行
    10 压缩和解压缩工具和bash脚本编程
    9 btrfs文件系统
  • 原文地址:https://www.cnblogs.com/lsy131479/p/8479232.html
Copyright © 2011-2022 走看看