论 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/

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

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏不会写文章的程序员不是好厨师

[翻译]Java 6,7,8中的String.intern

最近一直在关注“故障排查”的相关知识,首先着手的是OOM的异常。OOM异常通常会有Perm区的OOM(java7及以前)和HeapSpace的OOM,这两种各有...

672
来自专栏java达人

Java 8 Stream 教程 (三)

作者:Benjamin 译者:java达人 来源:http://winterbe.com/posts/2014/07/31/java8-stream-tuto...

1876
来自专栏老九学堂

干货 | 学编程一定要掌握的186个关键单词及作用!

很多初学Java的小伙伴们 经常会出现一些名称单词 却不知道其作用是什么 老九收集了186个Java入门常用的词汇, 为小伙伴们排忧解难 1抽象类(abstra...

3409
来自专栏函数式编程语言及工具

泛函编程(35)-泛函Stream IO:IO处理过程-IO Process

    IO处理可以说是计算机技术的核心。不是吗?使用计算机的目的就是希望它对输入数据进行运算后向我们输出计算结果。所谓Stream IO简单来说就是对一串按序...

18210
来自专栏斑斓

Scala的面向对象与函数编程

很难说FP和OO孰优孰劣,应该依场景合理选择使用。倘若从这个角度出发,Scala就体现出好处了,毕竟它同时支持了OO和FP两种设计范式。 从设计角度看,我认为O...

2945
来自专栏温安适的blog

Java8并行流写WordCount,并不简单

35810
来自专栏函数式编程语言及工具

Akka(7): FSM:通过状态变化来转换运算行为

  在上篇讨论里我们提到了become/unbecome。由于它们本质上是堆栈操作,所以只能在较少的状态切换下才能保证堆栈操作的协调及维持程序的清晰逻辑。对于比...

4908
来自专栏程序员维他命

《Effective Objective-C》干货三部曲(一):概念篇

本书是iOS程序员入门的必读书籍,它讲述了在iOS开发中(Objective-C语言)可以遵循的规范和一些开发技巧。

672
来自专栏欧阳大哥的轮子

深入解构objc_msgSend函数的实现

熟悉OC语言的Runtime(运行时)机制以及对象方法调用机制的开发者都知道,所有OC方法调用在编译时都会转化为对C函数objc_msgSend的调用。

542
来自专栏前端布道

JavaScript设计模式与开发实践 - 高阶函数的应用

定义 高阶函数是指至少满足下列条件之一的函数: 函数可以作为参数被传递; 函数可以作为返回值输出。 JavaScript语言中的函数显然满足高阶函数的条件,在实...

2983

扫描关注云+社区