精华内容
下载资源
问答
  • 问题是这样的,作为java新手,最近老搞不明白数据在内存中到底存放位置的问题。查了许多资料后,得出个结论,请有错误的帮忙指正,谢谢。 基本类型的数值会存放在栈中,执行效率高;引用对象(不包括String类型)的...
  • 点击进入_更多_Java千百问1、基本数据类型在内存中如何存放了解基本数据类型看这里:java有哪8种基本数据类型 对于java中的8种基本数据类型,可以通过如下方式赋值给变量赋值。int a = 3;float b = 4.0f;a = a + 2;...

    点击进入_更多_Java千百问

    1、基本数据类型在内存中如何存放

    了解基本数据类型看这里:java有哪8种基本数据类型
    对于java中的8种基本数据类型,可以通过如下方式赋值给变量赋值。

    int a = 3;
    
    float b = 4.0f;
    
    a = a + 2;

    8中基本数据是将具体值直接存放在中,在发生变更时,将具体值替换为新的值。具体如下:

    了解java如何管理内存看这里:jvm是如何管理内存的
    了解java堆和栈的区别看这里:java堆和栈有什么区别

    这里写图片描述

    对于基本数据类型,并没有基本数据池的概念,每次赋值并不会在栈中进行任何查询,而是直接存储值。

    但是,对于基本数据类型的包装器,在一定数值范围内是存放在运行时常量池中的。

    了解基本类型包装器看这里:什么是基本类型包装器
    了解运行时常量池看这里:运行时常量池是什么

    顺便提一句,对于基本数据类型,在内存中都是以二进制储存(当然,内存是以8位二进制作为一个存储单元,也就是一个字节),不同的类型所占用的内存空间(体现为存储单元)也不同。在java中,数值类型都是有符号存储(二进制首位为符号位),浮点类型也是遵循IEEE754、854标准

    了解二进制表示整型看这里:[用二进制如何表示整型数值][7]
    了解二进制表示浮点型看这里:[用二进制如何表示浮点型数值][8]

    对于一些不靠谱的资料或博客会混淆这个概念,认为基本数据类型在存储时首先回去看看栈中是否有该值,如果没有则放入,如果有则指向。这种说法纯属瞎扯,一个简单的道理,如果我分配了2G的栈内存,是否每次简单的int a = 1的赋值时,难道都会去排查一下这2g的空间?java没有这些人想象的这么无聊。

    展开全文
  • Java虚拟机执行Java程序的过程中会把它所管理的内存划分为若干个不同的数据区域,这些区域都有着各自的用途,以及创建和销毁的时间,有的区域随着虚拟机进程的启动而存在,有些区域则是依赖于用户进程的启动和结束...

    **Java内存存放区域与内存溢出异常(一)**

    Java虚拟机在执行Java程序的过程中会把它所管理的内存划分为若干个不同的数据区域,这些区域都有着各自的用途,以及创建和销毁的时间,有的区域随着虚拟机进程的启动而存在,有些区域则是依赖于用户进程的启动和结束而建立和销毁,java虚拟机所管理的内存将会包括以下几个运行时数据区域,如图一。


    1、在这里先介绍程序计数器

    程序计数器(Program Counter Register)是一块内存较小的内存空间,它的作用可以看作是当

    前线程所执行的字节码的行号指示器,在虚拟机的概念模型中,字节码解释器工作时就是通过改变这个

    计数器的值来选取下一条需要执行的字节码指令,分支、循环、跳转、异常处理、线程恢复等基础功能

    都需要依赖这个计数器来完成。

    由于Java虚拟机的多线程是通过线程轮流切换并分配处理器执行时间的方式来实现的,在任何一个确定的时刻,

    一个处理器只会执行一条线程中的指令,因此,为了切换后能恢复正确的执行位置,每条线程都需要一个独立的程序计数器,

    各条线程之间的计数器互不影响,独立存储,我们称这类内存存放区域为“线程私有的内存”。

    Java虚拟机栈

    Java虚拟机(Java Virtual Machine Stacks)与程序计数器相同,也是线程私有的,它的生命周期与线程,

    虚拟机栈描述的是Java方法执行的内存模型,每个方法被执行的时候都会同时创建一个栈帧,用于存储局部变量表、

    操作数栈、动态链接、方法出口等信息。每一个方法被调用直至执行完成的过程,就对应着一个栈帧在虚拟机从入

    栈到出栈的过程。

    局部变量表存放了八种基本数据类型(int,double,float,byte,char,short,long,boolean),以及对象引用

    (reference类型,它不等同于对象本身,根据不同的虚拟机实现,它可能是一个指向对象起始地址的引用指针,

    也可能指向一个代表对象的句柄或者其他与此对象相关的位置)和returnAddress类型(指向一条字节码指令的地址).

    3、本地方法栈

    本地方法栈(Native Method Stacks)与虚拟机栈所发挥的作用是非常相似的,其区别不过是虚拟机所执行的

    Java方法服务,而本地方法栈则是为虚拟机使用的Native方法服务,虚拟机规范中对本地方法栈中的方法使用的

    语言、使用方式、与数据结构并没有强制规定,因此具体的虚拟机可以自由实现它。

    4、Java堆

    Java堆(Java Heap)是Java虚拟机所管理的内存中最大的一块,Java堆是被所有是被所有线程共享的一块内

    存区域,在虚拟机启动时创建,此内存区域的唯一目的就是存放对象实例,几乎所有的对象实例都在这里分配内存,

    这一点在Java虚拟机规范中描述的是:所有的对象实例以及数组都要在堆上分配,但是随着JIT编译器的发展和逃逸

    分析技术逐渐成熟,栈上分配、标量替换优化技术都将会导致一些微妙的变化发生,所有的对象都分配在堆上也渐渐

    变得不是那么绝对了。

    Java堆是垃圾收集器管理的主要区域,因此很多时候也被称为GC堆,如果从内存回收的角度来看,由于现在的收

    集器都是采用分代收集算法,所以Java堆还可以细分为:新生代和老年代。不过,无论如何划分,都与存放内容无关,

    无论哪个区域,存储的都是对象实例,进一步划分的目的是为了更好的回收内存,或者更快的分配内存。

    5、方法区

    方法区(Method Area)与Java堆一样,是各个线程共享的内存区域,它用于存储已被虚拟机加载的类信息、

    常量、静态变量、及时编译器后的代码等数据,虽然Java虚拟机规范是把方法区描述为堆的一个逻辑部分,

    但是它却有一个别名叫做Non-Heap(非堆),目的可能是与Java堆区分开来。

    6、运行时常量池

    运行时常量池(Runtime Constant Pool)是方法区的一部分,Class文件中除了有类的版本、字段、方法、

    接口等描述信息外,还有一项信息是常量池(Constant Pool),用于存放编译期生成的各种字面量和符号引用。

    运行时常量池相对于Class文件常量池的另外一个重要特征是具备动态性,Java语言并不要求常量一定只

    能在编译期产生,也就是并非预置入Class文件中常量池的内容才能进入方法区运行时常量池,运行期间也可

    能将新的常量放入池中。

    Java内存存放区域和内存溢出异常就先讲到这里,下一节再写关于内存溢出所产生的异常。

    展开全文
  • a)基本数据类型 java的基本数据类型共有8种,即int,short,long,byte,...首先它会栈中创建一个变量为a的引用,然后查找有没有字面值为3的地址,没找到,就开辟一个存放3这个字面值的地址,然后a指向3的地址。接.

    a)基本数据类型

    java的基本数据类型共有8种,即int,short,long,byte,float,double,boolean,char(注意,并没有String的基本类型 )。8中基本数据类型存在于栈中。

    另外,栈有一个很重要的特殊性,就是存在栈中的数据可以共享。比如:
    我们同时定义:

    int a=3;
    int b=3;

    编译器先处理int a = 3;首先它会在栈中创建一个变量为a的引用,然后查找有没有字面值为3的地址,没找到,就开辟一个存放3这个字面值的地址,然后将a指向3的地址。接着处理int b = 3;在创建完b这个引用变量后,由于在栈中已经有3这个字面值,便将b直接指向3的地址。这样,就出现了a与b同时均指向3的情况。

    定义完a与b的值后,再令a = 4;那么,b不会等于4,还是等于3。在编译器内部,遇到时,它就会重新搜索栈中是否有4的字面值,如果没有,重新开辟地址存放4的值;如果已经有了,则直接将a指向这个地址。因此a值的改变不会影响到b的值。

    b)对象

    在java中,创建一个对象包括对象的声明和实例化两步,下面用一个例题来说明对象的内存模型。假设有类Person定义如下:

    public class Person {
        String name;
        int age;
        public Person(){
    
        }
        public Person(String name, int age) {
            this.name = name;
            this.age = age;
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public int getAge() {
            return age;
        }
    
        public void setAge(int age) {
            this.age = age;
        }
    
        @Override
        public String toString() {
            return "Person{" +
                    "name='" + name + '\'' +
                    ", age=" + age +
                    '}';
        }
    }
    

    (1)声明对象时的内存模型
    用Person p1;声明一个对象 p1 时,将在栈内存为对象的引用变量 p1 分配内存空间,但 Person 的值为空,称 p1 是一个空对象。空对象不能使用,因为它还没有引用任何”实体”。
    (2)对象实例化时的内存模型
    当执行 p1=new Person("w",5);时,会做两件事:在堆内存中为类的成员变量 name,age分配内存,并将其初始化为各数据类型的默认值;接着进行显式初始化(类定义时的初始化值);最后调用构造方法,为成员变量赋值。返回堆内存中对象的引用(相当于首地址)给引用变量 p1 ,以后就可以通过 p1 来引用堆内存中的对象了。

    一个类通过使用new运算符可以创建多个不同的对象实例,这些对象实例将在堆中被分配不同的内存空间,改变其中一个对象的状态不会影响其他对象的状态。例如:

            Person p1 = new Person();
            Person p2 = new Person();

    此时,将在堆内存中分别为两个对象的成员变量 name 、 age 分配内存空间,两个对象在堆内存中占据的空间是互不相同的。如果有:

            Person p1 = new Person();
            Person p2 = p1;

    则在堆内存中只创建了一个对象实例,在栈内存中创建了两个对象引用,两个对象引用同时指向一个对象实例。 

     

    c)包装类

    基本类型都有对应的包装类:如int对应Integer类,double对应Double类等,基本类型的定义都是直接在栈中,如果用包装类来创建对象,就和普通对象一样了。例如:int i=0;i直接存储在栈中。Integer i(i此时是对象)= new Integer(5);这样,i对象数据存储在堆中,i的引用存储在栈中,通过栈中的引用来操作对象。

    此外 Integer 包装类还存在越界的问题,当值在-128~127,Integer会先判断缓存中是否已经创建该数据,如果存在则拿来用就可以了,如下图中的 c 和 d 就指向同一个地址值,不存在则会创建。当创建的数据超过-128~127范围时,会新开辟一个缓存区,导致 e 和 f 的引用并不是指向同一个内存地址。

            int a = 100;
            Integer b = 100; //进行了自动装箱
            System.out.println(a == b);//true
            Integer c = 100;
            Integer d = 100;
            System.out.println(c == d); //true
            c = 200;
            d = 200;
            System.out.println(c == d); // false
            Integer e = new Integer(300);
            Integer f = new Integer(300);
            System.out.println(e==f); //false

    d)String

    String是一个特殊的包装类数据。可以用以下两种方式创建:

    1.String str = “abc”;

    2.String str = new String(“abc”);

    字符串的分配和其他的对象分配一样,需要耗费高昂的时间和空间为代价,如果需要大量频繁的创建字符串,会极大程度地影响程序的性能,因此 JVM 为了提高性能和减少内存开销引入了字符串常量池(Constant Pool Table)的概念。

    字符串常量池相当于给字符串开辟一个常量池空间类似于缓存区,对于直接赋值的字符串(String s="xxx"方式1创建)来说,在每次创建字符串时优先使用已经存在字符串常量池的字符串,如果字符串常量池没有相关的字符串,会先在字符串常量池中创建该字符串,然后将引用地址返回变量,如下图所示:

    而使用方式 2 创建 也就是说 new String 的方式会首先去判断字符串常量池,如果没有就会新建字符串那么就会创建 2 个对象,即现在常量池中创建一个,然后在堆中在创建一个并指向常量池,如果已经存在就只会在堆中创建一个对象指向字符串常量池中的字符串。

     

    下面我们先来看一道题:

            String a = "abc";
            String b = "abc";
            String b1 = "ab"+"c";
            String m = "a";
            String n = "bc";
            String mn = m+n;//会在堆上创建,有StringBuild执行append()
            System.out.println(a==mn); // false
            String c = new String("abc");
            String d = new String("abc");
            String e = new String("abc").intern();
            System.out.println(a==b); //true
            System.out.println(b==b1);//true
            System.out.println(b==c); //false
            System.out.println(c==d); //false
            System.out.println(a==e); //true
            System.out.println(d==e); // false

     其中 intern() 方法会直接得到常量池中的引用地址值返回给了 e ,所以 a == e 指向的是同一个地址。

     

    方法传递 string 变量也是一样的操作,如下所示

    public class demo01 {
        // 字符串,传递的是引用,形参与实参指向同一个常量池字符“dahua”,
        // 形参修改之后会在常量池新建一个常量池字符 “test success”,形参指向它,不影响实参
        String str = new String("dahua");
        char[] ch = {'a','b','c'};
        public static void main(String[] args) {
            demo01 d = new demo01();
            d.change(d.str,d.ch);
            System.out.println(d.str+"and");// 输出“dahua”
            System.out.println(d.ch);  //"gbc"
        }
        public void change(String str,char ch[]){
            str = "test success";
            ch[0] = 'g';
        }
    }
    
    字符串,传递给方法时仍然是引用,此时,形参与实参指向同一个常量池字符“dahua”,
    形参修改之后会在常量池新建一个常量池字符 “test success”,形参指向它,而不影响实参
    

     

    e)数组

    当定义一个数组,int x[];或int[] x;时,在栈内存中创建一个数组引用,通过该引用(即数组名)来引用数组。x=new int[3];将在堆内存中分配3个保存 int型数据的空间,堆内存的首地址放到栈内存中,每个数组元素被初始化为0。

    f)静态变量

    用static的修饰的变量会存放在方法区中

    那静态变量与方法是在什么时候初始化的呢?对于两种不同的类属性,static属性与instance属性,初始化的时机是不同的。instance属性在创建实例的时候初始化,static属性在类加载,也就是第一次用到这个类的时候初始化,对于后来的实例的创建,不再次进行初始化。

    展开全文
  • 首先它会栈中创建一个变量为a的引用,然后查找有没有字面值为3的地址,没找到,就开辟一个存放3这个字面值的地址,然后a指向3的地址? 是不是说要建立一个字面值为3的内存,再建立一个指向3的地址?就是要建立2...

    参考地址:https://www.zhihu.com/question/24747160

    问:int a = 3; 首先它会在栈中创建一个变量为a的引用,然后查找有没有字面值为3的地址,没找到,就开辟一个存放3这个字面值的地址,然后将a指向3的地址?
          是不是说要建立一个字面值为3的内存,再建立一个指向3的地址?就是要建立2个内存?

     

    答:
    	public void foo() {
    		int i = 100000000;
    		int j = 1;
    		Bar b = new Bar();
    	}
    

    上面代码编译成class文件之后

      public void foo();
        flags: ACC_PUBLIC
        Code:
          stack=2, locals=4, args_size=1
             0: ldc           #15                 // int 100000000
             2: istore_1      
             3: iconst_1      
             4: istore_2      
             5: new           #1                  // class Bar
             8: dup           
             9: invokespecial #16                 // Method "<init>":()V
            12: astore_3      
            13: return        
          LineNumberTable:
            line 3: 0
            line 4: 3
            line 5: 5
            line 6: 13
          LocalVariableTable:
            Start  Length  Slot  Name   Signature
                   0      14     0  this   LBar;
                   3      11     1     i   I
                   5       9     2     j   I
                  13       1     3     b   LBar;
    


    栈深度为2 本地变量表为4(对象方法对this的引用 存储i和j需要的地址 存储Bar用的地址)
    由于我代码中是写死的字面常量100000000 所以有个ldc命令去常量池里读了
    #15 = Integer            100000000
    

    这个常量 然后调用store命令存入了本地变量表的第Name为1的位置
    然后后边的int j = 1; 直接调用了iconst_1(这个1都没有存到类的常量池里..)获取了值为1的常量 然后存储到了Name为2的位置
    然后Bar对象是引用类型 所以是LBar
    例子并不全 你可以自己加一些代码 比如你加一个 int h = i + j;
    你就会发现他通过iload命令读取加载变量表中指定位置的值到栈中 然后调用iadd自动从栈中弹出两个之前加载的int值进行计算 栈深度其实就是指他一次能加载多少变量到栈

    这个不容易理解,找本虚拟机的书 了解下基本指令 然后对照自己的class文件 就明白了

    转载于:https://www.cnblogs.com/1020182600HENG/p/7305388.html

    展开全文
  • 根据线性表的实际存储方式,分为两种实现模型:顺序表 ,元素顺序地存放在一块连续的存储区里,元素间的顺序关系由它们的存储顺序自然表示。链表 ,元素存放在通过链接构造起来的一系列存储块中。一、顺序表在...
  • 内存分配的方式静态存储区, 编译时就已经分配好内存 , 这块的内存在成语运行中一直存活, 主要存放静态数据 , 全局变量 , static常量栈内存在执行函数时,存放函数内部变量,函数结束时,存储单元自动被释放。...
  • Java虚拟机所管理的内存中最大的一块。由所有线程共享,虚拟机启动时创建。堆区唯一目的就是存放对象实例。 是垃圾收集器管理的主要区域,因此很多时候也被称为“GC堆”。 二)方法区 jd...
  • 又称Non-Heap(非堆),主要用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据,根据Java 虚拟机规范的规定,当方法区无法满足内存分配需求时,抛出OutOfMemoryError 异常。...
  • 基本数据类型和引用数据类型使用的内存情况是不同的,基本数据类型只在栈中开辟内存,一旦使用结束(例如函数或方法内的数据),栈中的内存就会自动释放,然而引用数据类型会对象存放在栈中,而真正的值存放在堆...
  • 栈、堆、常量池虽同属Java内存分配时操作的区域,...一般Java在内存分配时会涉及到以下区域:◆寄存器:我们在程序中无法控制◆栈:存放基本类型的数据和对象的引用,但对象本身不存放在栈中,而是存放在堆中◆堆:...
  • 本文全面讲解Java虚拟机中的内存模型和分区。Java虚拟机把管理的内存划分为几个不同的数据区域,如下图所示。 下面就分别展开讲解一下每个区域的功能。1. JavaJava堆是被所有线程共享的一块内存区域,虚拟机...
  • 类加载是指.class类中的二进制数据存放到内存中,会在内存中的推中建立一个java.lang.String的引用对象来存放方法区的数据结构,而类中的数据会放到方法区中类加载器不需要等到某个类要用的时候在加载他,jvm允许...
  • 栈、堆、常量池虽同属Java内存分配时操作的区域,但其适用范围和...一般Java在内存分配时会涉及到以下区域:◆寄存器:我们在程序中无法控制◆栈:存放基本类型的数据和对象的引用,但对象本身不存放在栈中,而是存...
  • 临近春节,最近有点时间,准备顺着上篇专栏的思路写下去,建议先阅读:juejin.im/post/684490…武汉那几个吃野味的傻[],请藏好你们的妈正文开始运行Java程序时,java虚拟机需要使用内存存放各式各样的数据。...
  • public classJVMPrimaryDataDemo {//对于当前常量数据,类加载期间时class文件转为Class对象后,初始化时会当前数据存放到run-time constant pool 区域public static final int CONSTANT_COMPILER_DATA = 1;...
  • 类加载是指.class类中的二进制数据存放到内存中,会在内存中的推中建立一个java.lang.String的引用对象来存放方法区的数据结构,而类中的数据会放到方法区中 类加载器不需要等到某个类要用的时候在加载他,jvm...
  • 分区Java虚拟机运行Java程序时,会管理着一块内存区域:运行时数据运行时数据区里,会根据用途进行划分:Java虚拟机栈(栈区)本地方法栈Java堆(堆区)方法区程序计数器示意图下面,我详细介绍每个内存模型...
  • java内存泄漏

    2014-07-05 08:41:17
    在Java程序中,这个引用变量本身既可以存放内存中,又可以放在代码栈的内存中(与基本数据类型相同)。GC线程会从代码栈中的引用变量开始跟踪,从而判定哪些内存是正在使用的。如果GC线程通过这种方式,无法跟踪到...
  • 栈:存放基本数据类型(会包含这个基本类型的具体数值),引用对象的变量(会存放这个引用堆里面的具体地址) 方法区:可以被所有的线程共享,包含了所有class和static变量 类的加载过程: 当程序主动使用某个类时...
  • 分区Java虚拟机运行Java程序时,会管理着一块内存区域:运行时数据运行时数据区里,会根据用途进行划分:Java虚拟机栈(栈区)本地方法栈Java堆(堆区)方法区程序计数器下面,我详细介绍每个内存模型分区2....
  • Java 内存分区讲解

    千次阅读 多人点赞 2019-07-25 11:19:46
    本文全面讲解Java虚拟机中的内存模型和分区。 Java虚拟机把管理的内存划分为几个不同的数据区域,如下图所示。 下面就分别展开讲解一下每个区域的功能。 1. JavaJava堆是被所有线程共享的一块内存区域,...
  • 栈、堆、常量池等虽同属Java内存分配时操作的区域,但其适用范围和功用却大不相同。本文深入Java核心,简单讲解Java...如果是引用类型,则变量名存入栈,然后指向它new出的对象(存放在堆中)。 heap(堆):...
  • 栈、堆、常量池等虽同属Java内存分配时操作的区域,但其适用范围和功用却大不相同。本文深入Java核心,简单讲解Java内存分配方面的...如果是引用类型,则变量名存入栈,然后指向它new出的对象(存放在堆中)。h...
  • 栈、堆、常量池等虽同属Java内存分配时操作的区域,但其适用范围和功用却大不相同。本文深入Java核心,简单讲解Java内存分配方面的...如果是引用类型,则变量名存入栈,然后指向它new出的对象(存放在堆中)。h...
  • Java虚拟机运行Java程序时,会管理着一块内存区域:运行时数据运行时数据区里,会根据用途进行划分: Java虚拟机栈(栈区) 本地方法栈 Java堆(堆区) 方法区 程序计数器 下面,我详细介绍每个内存模型...
  • Java内存分配原理

    2019-10-02 22:43:14
    本文详细介绍一下Java在内存分配方面的知识。一般Java在内存分配时会涉及到以下区域: ◆寄存器:我们在程序中无法控制 ◆栈:存放基本类型的数据和对象的引用,但对象本身不存放在栈中,而是存放在堆中 ◆堆:...
  • Java虚拟机内存模型

    2018-08-11 14:56:44
    JVM虚拟机内存数据分为程序计数器、虚拟机、本地方法栈、Java堆和方法区等部分。 程序计数器用于存放下一条运行的指令。虚拟机栈和本地方法栈用于存放函数调用堆栈信息。Java堆用于存放Java程序运行时所需的...
  • java内存分配

    2020-01-16 23:56:47
    序言: ...图书编号是什么,等等一系列的操作,而我们编写代码就如同捐赠书籍,在你看不到的区域还在进行一系列的操作,你的数据存放在合适的位置,这就是java内存分配。 java内存区域划分 ...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 907
精华内容 362
热门标签
关键字:

java将数据存放在内存

java 订阅