精华内容
下载资源
问答
  • 本文主要介绍了JVM中堆内存和栈内存区别,具有很好的参考价值,下面跟着小编一起来看下吧
  • 主要介绍了java 中的堆内存和栈内存的知识,有需要的朋友可以参考下
  • Java堆内存和栈内存

    2020-12-22 15:22:30
     在函数中定义的一些基本类型的变量对象的引用变量都是在函数的栈内存中分配。当在一段代码块中定义一个变量时,java在栈中为这个变量分配内存空间,当超过变量的作用域后,java会自动释放掉为该变量分配的内存...
  • 堆内存和栈内存详解.doc 堆内存和栈内存详解.doc 堆内存和栈内存详解.doc
  • java堆内存和栈内存区别

    千次阅读 2015-11-03 14:05:48
    一段时间之前,我写了两篇文章文章分别是Java的垃圾回收Java的值传递,从那之后我收到了很多要求解释Java堆内存和栈内存的邮件,并且要求解释他们的异同点。在Java中你会看到很多堆和栈内存的引用,JavaEE书文章...

    一段时间之前,我写了两篇文章文章分别是Java的垃圾回收和Java的值传递,从那之后我收到了很多要求解释Java堆内存和栈内存的邮件,并且要求解释他们的异同点。

    在Java中你会看到很多堆和栈内存的引用,JavaEE书和文章很难在程序的角度完全解释什么是堆什么是栈。

    Java堆内存

    堆内存在Java运行时被使用来为对象和JRE类分配内存。不论什么时候我们创建了对象,它将一直会在堆内存上创建。垃圾回收运行在堆内存上来释放没有任何引用的对象所占的内存,任何在堆上被创建的对象都有一个全局的访问,并且可以在应用的任何位置被引用。

    Java栈内存

    Java的栈内存被用来线程的执行,他们包含生命周期很短的具体值的方法和在堆中使用这个方法对象的引用。栈内存是LIFO(后进先出)序列。当方法被调用的时候,堆内存中一个新的块被创建,保存了本地原始值和在方法中对其他对象的引用。这个方法结束之后,这个块对其他方法就变成可用的了。栈内存与堆内存相比是非常小的。
    我们用下边的例子理解堆内存和栈内存
    package com.journaldev.test;
     
    public class Memory {
     
        public static void main(String[] args) { // Line 1
            int i=1; // Line 2
            Object obj = new Object(); // Line 3
            Memory mem = new Memory(); // Line 4
            mem.foo(obj); // Line 5
        } // Line 9
     
        private void foo(Object param) { // Line 6
            String str = param.toString();  Line 7
            System.out.println(str);
        } // Line 8
     
    }

    下边的图片展示了上边程序堆和栈内存的引用,并且是怎么用来存储原始值、对象和变量的引用。
     
    我们来看看程序执行的过程:
    1、只要我们一运行这个程序,它会加载所有的运行类到堆内存中去,当在第一行找到main()方法的时候,Java创建可以被main()方法线程使用的栈内存。
    2、当在第一行,我们创建了本地原始变量,它在main()的栈中创建和保存。
    3、因为我们在第三行创建了对象,它在堆内存中被创建,在栈内存中保存了它的引用,同样的过程也发生在第四行我们创建Memory对象的时候。
    4、当在第五行我们调用foo()方法的时候,在堆的顶部创建了一个块来被foo()方法使用,因为Java是值传递的,在第六行一个新的对象的引用在foo()方法中的栈中被创建
    5、在第七行一个String被创建,它在堆空间中的 String池中运行,并且它的引用也在foo()方法的栈空间中被创建
    6、foo()方法在第八行结束,此时在堆中为foo()方法分配的内存块可以被释放
    7、在第九行,main()方法结束,栈为main()方法创建的内存空间可以被销毁。同样程序也在行结束,Java释放了所有的内存,结束了程序的运行

    堆内存和栈内存的区别

    基于上边的解释我们可以很简单的总结出堆和栈的区别:
    1、应用程序所有的部分都使用堆内存,然后栈内存通过一个线程运行来使用。
    2、不论对象什么时候创建,他都会存储在堆内存中,栈内存包含它的引用。栈内存只包含本地原始变量和堆中对象变量的引用。
    3、存储在堆中的对象是全局可以被访问的,然而栈内存不能被其他线程所访问。
    4、栈中的内存管理使用LIFO的方式完成,而堆内存的管理要更复杂了,因为它是全局被访问的。堆内存被分为,年轻一代,老一代等等,更多的细节请看, 这篇文章
    5、栈内存是生命周期很短的,然而堆内存的生命周期从程序的运行开始到运行结束。
    6、我们可以使用-Xms和-Xmx JVM选项定义开始的大小和堆内存的最大值,我们可以使用-Xss定义栈的大小
    7、当栈内存满的时候,Java抛出java.lang.StackOverFlowError异常而堆内存满的时候抛出java.lang.OutOfMemoryError: Java Heap Space错误
    8、和堆内存比,栈内存要小的多,因为明确使用了内存分配规则(LIFO),和堆内存相比栈内存非常快。
     

    原文地址:http://www.journaldev.com/4098/java-heap-memory-vs-stack-memory-difference

    关注我,获取400个的赚钱金点子,轻松开启程序员的副业生涯

     

    展开全文
  • 堆内存和栈内存区别

    万次阅读 2019-03-14 00:03:46
    总结: 1 栈:为编译器自动分配释放,如函数参数、局部变量、临时变量等等 2 堆:为成员分配释放,由程序员自己申请、自己释放。否则发生内存泄露。...栈内存和堆内存区别(一个笔试题的一部分)http://...


    总结:
    1 栈:为编译器自动分配和释放,如函数参数、局部变量、临时变量等等
    2 堆:为成员分配和释放,由程序员自己申请、自己释放。否则发生内存泄露。典型为使用new申请的堆内容。

    除了这两部分,还有一部分是:
    3 静态存储区:内存在程序编译的时候就已经分配好,这块内存在程序的整个运行期间都存在。它主要存放静态数据、全局数据和常量。

    转自:
    栈内存和堆内存的区别(一个笔试题的一部分)http://blog.csdn.net/richerg85/article/details/19175133


    笔试题目:请解释一个栈内存与一个堆内存的区别,请分析下面代码运行是否有问题,如果有问题请改正。

    char* GetMemory(void)

    {

    char p[] = "Hello world";

    return p;

    }

    void main(void)

    {

    char* str = GetMemory();

    printf(str);

    }

    先看第一个问题:栈内存和堆内存的区别

    程序的内存分配
    栈(stack):有编译器自动分配和释放,存放函数的参数、局部变量、临时变量、函数返回地址等;

    堆(heap):一般有程序员分配和释放,如果没有手动释放,在程序结束时可能由操作系统自动释放(?这个可能针对Java那样的有回收机制的语言而说的,对于c/c++,这样的必须要手动释放开辟的堆内存),稍有不慎会引起内存泄漏。

    2.申请后系统的响应

    栈:只要栈的剩余空间大于所申请的空间,系统将为程序提供内存,否则将报异常提示栈溢出。

    堆:在记录空闲内存地址的链表中寻找一个空间大于所申请空间的堆结点,然后将该结点从空闲结点链表中删除,并将该结点的空间分配给程序。另外,对于大多数系统会在这块内存空间的首地址出记录本次分配空间的大小,这样代码中的delete 才能正确释放本内存空间。系统会将多余的那部分重新空闲链表中。

    3、申请大小限制
    栈:在Windows下,栈是向低地址扩展的数据结构,是一块连续的内存的区域。这句话的意思是栈顶的地址和栈的最大容量是系统预先规定好的,在 WINDOWS下,栈的大小是2M(也有的说是1M,总之是一个编译时就确定的常数),如果申请的空间超过栈的剩余空间时,将提示overflow。因此,能从栈获得的空间较小。
    堆:堆是向高地址扩展的数据结构,是不连续的内存区域。这是由于系统是用链表来存储的空闲内存地址的,自然是不连续的,而链表的遍历方向是由低地址向高地址。堆的大小受限于计算机系统中有效的虚拟内存。由此可见,堆获得的空间比较灵活,也比较大。
    4、分配效率
    栈:由系统自动分配,速度较快。但程序员是无法控制的。
    堆:由new分配的内存,一般速度比较慢,而且容易产生内存碎片,不过用起来最方便. 另外,在WINDOWS下,最好的方式是用VirtualAlloc分配内存,不是在堆,也不是在栈是直接在进程的地址空间中保留一快内存,虽然用起来最不方便。但是速度快,也最灵活
    5、存储内容

    栈:在栈中,第一个进栈的是主函数下一条指令的地址,然后是函数的各个参数,在大多数编译器中,参数是由右往左入栈,然后是函数中的局部变量。注意,静态变量不入栈。出栈则刚好顺序相反。

    堆:一般在堆的头部用一个字节存放堆的大小,具体内容由程序员安排。

     


    根据《C++内存管理技术内幕》一书,在C++中,内存分成5个区,他们分别是堆,栈,自由存续区,全局/静态存续区,常量存续区。

      a) 栈:内存由编译器在需要时自动分配和释放。通常用来存储局部变量和函数参数。(为运行函数而分配的局部变量、函数参数、返回地址等存放在栈区)。栈运算分配内置于处理器的指令集中,效率很高,但是分配的内存容量有限。

      b) 堆:内存使用new进行分配,使用delete或delete[]释放。如果未能对内存进行正确的释放,会造成内存泄漏。但在程序结束时,会由操作系统自动回收。

      c) 自由存储区:使用malloc进行分配,使用free进行回收。和堆类似。

      d) 全局/静态存储区:全局变量和静态变量被分配到同一块内存中,C语言中区分初始化和未初始化的,C++中不再区分了。(全局变量、静态数据、常量存放在全局数据区)

      e) 常量存储区:存储常量,不允许被修改。

      这里,在一些资料中是这样定义C++内存分配的,可编程内存在基本上分为这样的几大部分:静态存储区、堆区和栈区。他们的功能不同,对他们使用方式也就不同。

      a)静态存储区:内存在程序编译的时候就已经分配好,这块内存在程序的整个运行期间都存在。它主要存放静态数据、全局数据和常量。

      b)栈区:在执行函数时,函数内局部变量的存储单元都可以在栈上创建,函数执行结束时这些存储单元自动被释放。栈内存分配运算内置于处理器的指令集中,效率很高,但是分配的内存容量有限。

      c)堆区:亦称动态内存分配。程序在运行的时候用malloc或new申请任意大小的内存,程序员自己负责在适当的时候用free或 delete释放内存。动态内存的生存期可以由我们决定,如果我们不释放内存,程序将在最后才释放掉动态内存。 但是,良好的编程习惯是:如果某动态内存不再使用,需要将其释放掉,否则,我们认为发生了内存泄漏现象。

    \
      图3 典型c++内存区域

      总结:C++与C语言的内存分配存在一些不同,但是整体上就一致的,不会影响程序分析。就C++而言,不管是5部分还是3大部分,只是分法不一致,将5部分中的c)d)e)合在一起则是3部分的a)。

     

     

    下面几段代码,则会让你有豁然明白的感觉:
    void fn()

    {

    int* p = new int[5];

    }

      看到new,首先应该想到,我们分配了一块堆内存,那么指针p呢? 它分配的是一块栈内存,所以这句话的意思就是:在栈内存中存放了一个指向一块堆内存的指针p。程序会先确定在堆中分配内存的大小,然后调用 operator new分配内存,然后返回这块内存的首地址,放入栈中。

      注意:这里为了简单并没有释放内存,那么该怎么去释放呢? 是deletep么? NO,错了,应该是delete [ ] p,这是告诉编译器:删除的是一个数组。


    //main.cpp
    int a = 0; 全局初始化区
    char *p1; 全局未初始化区
    main()
    {
    int b; 栈
    char s[] = "abc"; 栈
    char *p2; 栈
    char *p3 = "123456"; 123456\0在常量区,p3在栈上。
    static int c =0; 全局(静态)初始化区
    p1 = (char *)malloc(10);
    p2 = (char *)malloc(20);
    分配得来得10和20字节的区域就在堆区。
    strcpy(p1, "123456"); 123456\0放在常量区,编译器可能会将它与p3所指向的"123456"优化成一个地方。

    展开全文
  • 基础知识篇——堆内存和栈内存

    万次阅读 多人点赞 2018-11-01 09:05:00
    数据结构中的堆和栈 是一种连续储存的数据结构,具有先进后出的性质。 通常的操作有入栈(压栈),出栈栈顶元素。想要读取中的某个元素,就是将其之间的所有元素出栈才能完成。 是一种非连续的树形储存...

    一、数据结构中的堆和栈

    1. 栈

    是一种连续储存的数据结构,具有先进后出的性质。

    通常的操作有入栈(压栈),出栈和栈顶元素。想要读取栈中的某个元素,就是将其之间的所有元素出栈才能完成。

    2. 堆

    是一种非连续的树形储存数据结构,每个节点有一个值,整棵树是经过排序的。特点是根结点的值最小(或最大)且根结点的两个子树也是一个堆。常用来实现优先队列,存取随意。



    二、内存中的栈区与堆区

    1. 内存中的栈区与堆区比较

    栈区堆区
    Stack memory内存空间由操作系统自动分配和释放。Heap Memory内存空间手动申请和释放的,Heap Memory内存常用new关键字来分配
    Stack Memory内存空间有限。Heap Memor的空间是很大的自由区几乎没有空间限制。

    2. 计算机内存的大致划分

    一般说到内存,指的是计算机的随机存储器(RAM),程序都是在这里面运行。



    三、栈内存与栈溢出

    由程序自动向操作系统申请分配以及回收,速度快,使用方便,但程序员无法控制。只要栈的剩余空间大于所申请的空间,系统将为程序提供内存,否则将报异常提示栈溢出,即若分配失败,则提示栈溢出错误。

    在Windows下,栈是向低地址扩展的数据结构,是一块连续的内存的区域。这句话的意思是栈顶的地址和栈的最大容量是系统预先规定好的,在 WINDOWS下,栈的大小是2M(也有的说是1M,总之是一个编译时就确定的常数),如果申请的空间超过栈的剩余空间时,将提示overflow。

    因此,能从栈获得的空间较小。

    😒 注意,const局部变量也储存在栈区内,栈区向地址减小的方向增长。

    	#include <iostream>
    	int main()
    	{
    	    int i = 10; //变量i储存在栈区中
    	    const int i2 = 20;
    	    int i3 = 30;
    	    std::cout << &i << " " << &i2 << " " << &i3 << std::endl;
    	    return 0;
    	}
    

    在这里插入图片描述
    &i3 < &i2 < &i,证明地址是减小的。





    四、堆内存与内存泄露

    程序员向操作系统申请一块内存,当系统收到程序的申请时,会遍历一个记录空闲内存地址的链表,寻找第一个空间大于所申请空间的堆结点,然后将该结点从空闲结点链表中删除,并将该结点的空间分配给程序

    • 分配的速度较慢,地址不连续,容易碎片化。
    • 由程序员申请,同时也必须由程序员负责销毁,否则导致内存泄露

    堆是向高地址扩展的数据结构,是不连续的内存区域。这是由于系统是用链表来存储的空闲内存地址的,自然是不连续的,而链表的遍历方向是由低地址向高地址。堆的大小受限于计算机系统中有效的虚拟内存。由此可见,堆获得的空间比较灵活,也比较大。

    //测试堆内存和栈内存的区别
    #include <iostream>
    int main()
    {
        int i = 10;               //变量i储存在栈区中
        char pc[] = "hello!";     //储存在栈区
        const double cd = 99.2;   //储存在栈区
        static long si = 99;      //si储存在可读写区,专门用来储存全局变量和静态变量的内存
        int* pi = new int(100);   //指针pi指向的内存是在堆区,专门储存程序运行时分配的内存
        std::cout << &i << " " << &pc << " " << &cd << " " << &si << " " << pi << std::endl;
        delete pi;                //需程序员自己释放
        return 0;
    }
    

    在这里插入图片描述

    五、JAVA

    1. Java中的堆与栈

    在Java中:

    • 声明的对象是先在栈内存中为其分配地址空间,
    • 在对其进行实例化后则在堆内存中为其分配地址。

    例如:
    Person p = null ; 只在Stack Memory中为其分配地址空间
    p = new Person(); 则在Heap Memory中为其分配内存地址


    在函数中定义的一些基本类型的变量和对象的引用变量都是在函数的栈内存中分配,

    • 当在一段代码块定义一个变量时,Java就在中为这个变量分配内存空间,
    • 当超过变量的作用域后,Java 会自动释放掉为该变量分配的内存空间,该内存空间可以立即被另作它用。

    堆内存用来存放由 new 创建的对象和数组,在堆中分配的内存,由 Java 虚拟机的自动垃圾回收器来管理。

    2. 引用变量

    在堆中产生了一个数组或者对象之后,还可以在栈中定义一个特殊的变量,让栈中的这个变量的取值等于数组或对象在堆内存中的首地址,栈中的这个变量就成了数组或对象的引用变量,以后就可以在程序中使用栈中的引用变量来访问堆中的数组或者对象,引用变量就相当于是为数组或者对象起的一个名称

    引用变量是普通的变量,定义时在栈中分配,引用变量在程序运行到其作用域之外后被释放。

    而数组和对象本身在堆中分配,即使程序运行到使用 new 产生数组或者对象的语句所在的代码块之外,数组和对象本身占据的内存不会被释放,数组和对象在没有引用变量指向它的时候,才变为垃圾,不能在被使用,但仍然占据内存空间不放,在随后的一个不确定的时间被垃圾回收器收走(释放掉)。

    3. 堆和非堆内存

    按照官方的说法:“Java 虚拟机具有一个堆,堆是运行时数据区域,所有类实例和数组的内存均从此处分配。 堆是在 Java 虚拟机启动时创建的。在JVM中,堆之外的内存称为非堆内存(Non-heap memory)”

    可以看出JVM主要管理两种类型的内存:堆和非堆。
    简单来说:

    • 堆就是Java代码可及的内存,是留给开发人员使用的;
    • 非堆就是JVM留给自己用的,所以
      1. 方法区、
      2. JVM内部处理或优化所需的内存(如JIT编译后的代码缓存)、
      3. 每个类结构(如运行时常数池、字段和方法数据)
      4. 方法和构造方法 的代码

    都在非堆内存中。
    在这里插入图片描述

    六、《C++内存管理技术内幕》

    1. C++中,内存分成5个区

    根据《C++内存管理技术内幕》一书,在C++中,内存分成5个区,分别是:堆、栈、自由存储区、全局/静态存储区、常量存储区。

    a)栈

    内存由编译器在需要时自动分配和释放。通常用来存储局部变量函数参数

    为运行函数而分配的局部变量、函数参数、返回地址等存放在栈区。

    栈运算分配内置于处理器的指令集中,效率很高,但是分配的内存容量有限。

    b)堆

    内存使用new进行分配,使用delete或delete[]释放。

    如果未能对内存进行正确的释放,会造成内存泄漏

    但在程序结束时,会由操作系统自动回收

    c)自由存储区

    使用malloc进行分配,使用free进行回收
    和堆类似。

    d)全局/静态存储区

    全局变量和静态变量被分配到同一块内存中,C语言中区分初始化和未初始化的,C++中不再区分了。

    全局变量、静态数据、常量存放在全局数据区;使用静态关键字static声明,在静态存储区申请一个静态变量。

    e)常量存储区

    存储常量,不允许被修改。

    2. C++中,内存分成3个区

    这里,在一些资料中是这样定义C++内存分配的,可编程内存在基本上分为这样的几大部分:静态存储区、堆区和栈区。他们的功能不同,对他们使用方式也就不同。

    a)静态存储区

    内存在程序编译的时候就已经分配好,这块内存在程序的整个运行期间都存在。它主要存放静态数据、全局数据和常量。

    b)栈区

    在执行函数时,函数内局部变量的存储单元都可以在栈上创建,函数执行结束时这些存储单元自动被释放。

    栈内存分配运算内置于处理器的指令集中,效率很高,但是分配的内存容量有限。

    c)堆区

    亦称动态内存分配。

    程序在运行的时候用malloc或new申请任意大小的内存,程序员自己负责在适当的时候用free或 delete释放内存。

    动态内存的生存期可以由我们决定,如果我们不释放内存,程序将在最后才释放掉动态内存。

    但是,良好的编程习惯是:如果某动态内存不再使用,需要将其释放掉,否则,我们认为发生了内存泄漏现象

    七、堆和栈究竟有什么区别?

    管理方式不同

    • 对于栈来讲,是由编译器自动管理,无需我们手工控制
    • 对于堆来说,释放工作由程序员控制,容易产生memory leak

    空间大小不同

    • 一般来讲在32位系统下,堆内存可以达到4G的空间,从这个角度来看堆内存几乎是没有什么限制的。
    • 对于栈来讲,一般都是有一定的空间大小的。默认的栈空间大小是1M了。不过可以修改其大小。

    能否产生碎片不同

    • 对于堆来讲,频繁的new/delete势必会造成内存空间的不连续,从而造成大量的碎片,使程序效率降低。
    • 对于栈来讲,则不会存在这个问题,因为栈是先进后出的队列,他们是如此的一一对应,以至于永远都不可能有一个内存块从栈中间弹出,在他弹出之前,在他上面的后进的栈内容已经被弹出。

    生长方向不同

    • 对于堆来讲,生长方向是向上的,也就是向着内存地址增加的方向;
    • 对于栈来讲,它的生长方向是向下的,是向着内存地址减小的方向增长。

    分配方式不同

    • 堆都是动态分配的,没有静态分配的堆。
    • 栈有2种分配方式:静态分配和动态分配。静态分配是编译器完成的,比如局部变量的分配。动态分配由allocal 函数进行分配,但是栈的动态分配和堆是不同的,他的动态分配是由编译器进行释放,无需我们手工实现。

    分配效率不同

    • 栈是机器系统提供的数据结构,计算机会在底层对栈提供支持:分配专门的寄存器存放栈的地址,压栈出栈都有专门的指令执行,这就决定了栈的效率比较高
    • 堆则是C/C++函数库提供的,它的机制是很复杂的,例如为了分配一块内存,库函数会按照一定的算法(具体的算法可以参考数据结构/操作系统)在堆内存中搜索可用的足够大小的空间,如果没有足够大小的空间(可能是由于内存碎片太多),就有可能调用系统功能去增加程序数据段的内存空间,这样就有机会分到足够大小的内存,然后进行返回。显然,堆的效率比栈要低得多

    总结

    可以看到,堆和栈相比,由于大量new/delete的使用,容易造成大量的内存碎片;由于没有专门的系统支持,效率很低;由于可能引发用户态和核心态的切换,内存的申请,代价变得更加昂贵。所以栈在程序中是应用最广泛的,就算是函数的调用也利用栈去完成,函数调用过程中的参数,返回地址,EBP和局部变量都采用栈的方式存放。所以,推荐大家尽量用栈,而不是用堆。

    虽然栈有如此众多的好处,但是由于和堆相比不是那么灵活,有时候分配大量的内存空间,还是用堆好


    内存使用规则:
    【规则1】用malloc或new申请内存之后,应该立即检查指针值是否为NULL。防止使用指针值为NULL的内存。
    【规则2】不要忘记为数组和动态内存赋初值。防止将未被初始化的内存作为右值使用。
    【规则3】避免数组或指针的下标越界,特别要当心发生“多1”或者“少1”操作。
    【规则4】动态内存的申请与释放必须配对,防止内存泄漏。
    【规则5】用free或delete释放了内存之后,立即将指针设置为NULL,防止产生“野指针”。


    C++与C语言的内存分配存在一些不同,但是整体上就一致的,不会影响程序分析。就C++而言,不管是5部分还是3大部分,只是分法不一致,将5部分中的c)d)e)合在一起则是3部分的a)。

    下面几段代码,则会让你有豁然明白的感觉:

    void fn(){ 
       int* p = new int[5];
    }
    

    看到new,首先应该想到,我们分配了一块堆内存,那么指针p呢?
      它分配的是一块栈内存,所以这句话的意思就是:在栈内存中存放了一个指向一块堆内存的指针p。程序会先确定在堆中分配内存的大小,然后调用 operator new分配内存,然后返回这块内存的首地址,放入栈中
      
      注意:这里为了简单并没有释放内存,那么该怎么去释放呢? 是delete p么? NO,错了,应该是delete [ ]p,这是告诉编译器:删除的是一个数组。

    //main.cpp 
    int a = 0;   //全局初始化区 
    char *p1;    //全局未初始化区 
    main() 
    { 
    int b;               //栈 
    char s[] = "abc";    //栈 
    char *p2;            //栈 
    char *p3 = "123456"; //123456\0在常量区,p3在栈上。 
    static int c =0// 全局(静态)初始化区 
    
    // 分配得来得10和20字节的区域就在堆区。 
    p1 = (char *)malloc(10); 
    p2 = (char *)malloc(20); 
    strcpy(p1, "123456"); // 123456\0放在常量区,编译器可能会将它与p3所指向的"123456"优化成一个地方。 
    }
    

    学习:
    https://www.cnblogs.com/jiudianren/p/5671992.html
    https://msd.misuland.com/pd/2884250137616452012

    展开全文
  • 主要介绍了Java 堆内存栈内存详细介绍的相关资料,这里对java 的堆内存和栈内存进行了详细的分析,需要的朋友可以参考下
  • 堆内存和栈内存详解

    万次阅读 多人点赞 2014-10-04 17:50:01
    :顺序随意 :先进后出 堆和栈区别 一、预备知识—程序的内存分配 一个由c/C++编译的程序占用的内存分为以下几个部分 1、区(stack)— 由编译器自动分配释放 ,存放函数的参数值,局部变量的值等。...
    
    

    一、预备知识—程序的内存分配 

    一个由C/C++编译的程序占用的内存分为以下几个部分 
    1
    栈区stack)—由编译器自动分配释放 ,存放函数的参数值,局部变量的值等。其操作方式类似于数据结构中的栈 
    2
    堆区heap)— 一般由程序员分配释放,若程序员不释放,程序结束时可能由OS回收。注意它与数据结构中的堆是两回事,分配方式倒是类似于链表
    3
    、全局区(静态区)(static)—,全局变量和静态变量的存储是放在一块的,初始化的全局变量和静态变量在一块区域,未初始化的全局变量和未初始化的静态变量在相邻的另一块区域。-程序结束后有系统释放 
    4
    、文字常量区—常量字符串就是放在这里的。 程序结束后由系统释放 

    5、程序代码区—存放函数体的二进制代码。



    二、例子程序

    //main.cpp
    inta = 0; //全局初始化区
    char*p1; //全局未初始化区
    main()
    {
    int b; //栈 
       char s[] = "abc"; //栈 
       char *p2; //栈  
       char *p3 = "123456"; //123456\0在常量区,p3在栈上。  
       static int c =0; //全局(静态)初始化区 
       p1 = (char *)malloc(10);  
        p2 = (char*)malloc(20);  
       //分配得来的10和20字节的区域就在堆区, 但是注意p1、p2本身是在栈中的 
       strcpy(p1,"123456"); //123456\0放在常量区,编译器可能会将它与p3所指向的"123456"优化成一个地方。  
    } 




    三、堆和栈的理论知识 
    3.1
    申请后系统的响应 

    :只要栈的剩余空间大于所申请空间,系统将为程序提供内存,否则将报异常提示栈溢出。

    :首先应该知道操作系统有一个记录空闲内存地址的链表,当系统收到程序的申请时,会遍历该链表,寻找第一个空间大于所申请空间的堆结点,然后将该结点从空闲结点链表中删除,并将该结点的空间分配给程序,另外,对于大多数系统,会在这块内存空间中的首地址处记录本次分配的大小,这样,代码中的delete语句才能正确的释放本内存空间。另外,由于找到的堆结点的大小不一定正好等于申请的大小,系统会自动的将多余的那部分重新放入空闲链表中。 

    注意这里,malloc分配失败会返回空指针,但new分配失败只会抛出异常,需要

    catch( const bad_alloc& e ) {
               return-1;
    }



    3.2
    申请大小的限制 
    :在Windows,栈是向低地址扩展的数据结构,是一块连续的内存的区域。这句话的意思是栈顶的地址和栈的最大容量是系统预先规定好的,在WINDOWS下,由编译器决定栈的大小(一般1M/2M),如果申请的空间超过栈的剩余空间时,将提示overflow。因此,能从栈获得的空间较小。 
    堆是向高地址扩展的数据结构,是不连续的内存区域。这是由于系统是用链表来存储的空闲内存地址的,自然是不连续的,而链表的遍历方向是由低地址向高地址。堆的大小受限于计算机系统中有效的虚拟内存。由此可见,堆获得的空间比较灵活,也比较大。 


    3.3申请效率的比较

    : 由系统自动分配,速度较快。但程序员是无法控制的。 

    new分配的内存,一般速度比较慢,而且容易产生内存碎片,不过用起来最方便.另外,在WINDOWS下,最好的方式是用VirtualAlloc分配内存,他不是在堆,也不是在栈是直接在进程的地址空间中保留一快内存,虽然用起来最不方便。但是速度快,也最灵活。



    3.4堆和栈中的存储内容 
     在函数调用时,第一个进栈的是主函数中后的下一条指令(函数调用语句的下一条可执行语句)的地址,然后是函数的各个参数,在大多数的C编译器中,参数是由右往左入栈的,然后是函数中的局部变量。注意静态变量是不入栈的。当本次函数调用结束后,局部变量先出栈,然后是参数,最后栈顶指针指向最开始存的地址,也就是主函数中的下一条指令,程序由该点继续运行。 

    :一般是在堆的头部用一个字节存放堆的大小。堆中的具体内容由程序员安排。 


    3.5存取效率的比较 

    chars[] = "abc"; //栈 
    char*p3 = "123456"; //123456\0在常量区,p3在栈上。


    abc是在运行时刻赋值的;而123456是在编译时就确定的;但是,在以后的存取中,在栈上的数组比指针所指向的字符串(例如堆)快。 



    3.6小心内存泄漏

    在堆上分配内存很容易造成内存泄漏,这是C/C++的最大的“克星”,如果你的程序要稳定,那么就不要出现MemoryLeak。所以,我还是要在这里千叮咛万嘱付,在使用malloc系统函数(包括callocrealloc)时千万要小心。 

    记得有一个UNIX上的服务应用程序,大约有几百的C文件编译而成,运行测试良好,等使用时,每隔三个月系统就是down一次,搞得许多人焦头烂额,查不出问题所在。只好,每隔两个月人工手动重启系统一次。出现这种问题就是MemeryLeak在做怪了,在C/C++中这种问题总是会发生,所以你一定要小心。 
     

    对于mallocfree的操作有以下规则: 
    1)
    配对使用,有一个malloc,就应该有一个free。(C++中对应为newdelete) 
    2) 
    尽量在同一层上使用,不要malloc在函数中,而free在函数外。最好在同一调用层上使用这两个函数。 
    3) malloc
    分配的内存一定要初始化。free后的指针一定要设置为NULL。 

    注:虽然现在的操作系统(如:UNIXWin2k/NT)都有进程内存跟踪机制,也就是如果你有没有释放的内存,操作系统会帮你释放。但操作系统依然不会释放你程序中所有产生了MemoryLeak的内存,所以,最好还是你自己来做这个工作。(有的时候不知不觉就出现MemoryLeak了,而且在几百万行的代码中找无异于海底捞针,Rational有一个工具叫Purify,可能很好的帮你检查程序中的MemoryLeak





    展开全文
  • Java 堆内存和栈内存

    千次阅读 2016-03-23 19:59:12
    对Java中堆内存和栈内存的简单理解
  • 主要介绍了JAVA中堆内存栈内存区别,文中讲解非常细致,代码帮助大家更好的理解学习,感兴趣的朋友可以了解下
  • 堆内存和栈内存: 概念: 基本数据类型存储在栈内存中 引用数据类型存储在堆内存区别栈内存:由操作系统自动分配释放 堆内存:一般由程序员手动释放,否则将会由os来回收 ...
  • 堆内存和栈内存

    2012-12-30 19:13:08
    两个术语虽然只有一字之差,但是所表达的意义还是有差别的,堆内存和栈内存区别可以用如下的比喻来看出:使用堆内存就象是自己动手做喜欢吃的菜肴,比较麻烦,但是比较符合自己的口味,而且自由度大。使用栈内存就...
  • 浅析Java堆内存和栈内存区别

    万次阅读 2018-03-06 09:36:55
    参考 堆内存:https://baike.baidu.com/item/%E5%A0%86%E5%86%85%E5%AD%98/7270805?fr=aladdin ...Java把内存划分成两种:一种是栈内存,一种是堆内存。 一、栈内存 存放基本类型的变量,对象的引用和方...
  • JAVA内存管理之堆内存和栈内存

    千次阅读 2013-06-18 19:11:31
    我们常常做的是将Java内存区域简单的划分为两种:堆内存和栈内存。这种划分比较粗粒度,这种划分是着眼于我们最关注的、与对象内存分配密切相关的两类内存域。其中栈内存指的是虚拟机栈,堆内存指的是java堆。 1....
  • 关于堆内存和栈内存释放

    千次阅读 2019-06-28 20:47:18
    js 中的内存分为堆内存和 栈内存 堆内存:存储引用类型值 (对象:键值对 函数:代码字符串) 栈内存: 提供JS代码执行的环境存储基本类型值 堆内存释放 让所有引用堆内存空间地址的变量赋值给Null 即可 (没有...
  • JAVA之堆内存和栈内存区别

    千次阅读 2018-01-25 12:30:45
    Java把内存分成两种,一种叫做栈内存,一种叫做内存在函数中定义的一些基本类型的变量对象的引用变量都是在函数的栈内存中分配。当在一段代码块中定义一个变量时,java就在栈中为这个变量分配内存空间,当超过...
  • JS中对象分为基本类型引用类型,基本类型存放在栈内存,引用类型存放在堆内存。请问栈内存和堆内存区别是什么,为什么这两种对象分别存储在不同的内存中?
  • [Java]Java的堆内存和栈内存解析–举例进行内存分析JavaJava的堆内存和栈内存解析举例进行内存分析 明确概念 堆内存Heap 栈内存Stack 两者联系 实例说明 代码 流程分析 内存分配策略 静态内存分配 栈式内存分配 堆式...
  • 详细的讲解了java内存分配,包括运行时堆和栈内存的分配,变量方法存储等
  • 堆内存和栈内存详解,我感觉挺好的,解释的很详细,大家可以参考一下啊!
  • JS的堆内存和栈内存

    千次阅读 多人点赞 2019-04-22 18:38:03
    用于复杂数据类型(引用类型)分配空间,例如数组对象、object对象(引用类型的值通常大小不固定,所以被存储在堆内存中,不会自动释放);它是运行时动态分配内存的,因此存取速度较慢。 (stack)     ...
  • 栈都是内存中的一部分,有着不同的作用,而且一个程序需要在这片区域上额分配内存,众所周知...最主要的区别就是栈内存用来存储局部变量方法调用,而堆内存用来存储java中的对象,无论是成员变量,局部变量还是类

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 330,225
精华内容 132,090
关键字:

堆内存和栈内存区别