JAVA/C++ 堆栈详解

本文探讨了Java和C++在内存分配上的差异,重点在于堆栈的使用。在C++中,局部对象存储在栈上,生命周期随函数结束而销毁,堆内存需手动释放。而在Java中,所有对象都在堆上创建,不需要手动释放。文章警告不要返回超出栈顶对象的引用或指针,并总结了两者在返回对象引用上的不同。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

最近在读《Thinking in Java 》,在博客上分享下笔记。小白入门,欢迎批评指正!

1. Java与C++在内存分配上的异同

内存区域共性C++Java
寄存器位于处理器内部,最快的存储区,由编译器根据需求进行分配,无法直接控制,也不能在程序中感觉到寄存器存在的任何迹象。C和C++允许向编译器建议寄存器的分配方式。
位于通用RAM中,由编译器自动分配释放,存放基本数据类型及对象引用等。创建程序时,系统知道存储在栈内的所有项的确切生命周期。C++的局部对象也分配在栈中,函数结束后对象被自动销毁。Java不允许创建局部对象,所以Java对象永远不可能存储于此
位于RAM区,供程序员分配的内存区域(new、malloc)C++中new、malloc创建的对象或分配的内存空间,使用完后必须手动释放delete、free,否则可能会出现内存泄漏Java中new出来的对象或数组。由JVM垃圾回收器进行管理,使用后无需手动释放。
其他静态区、文字常量区、程序代码区方法区(也叫静态区),存放整个程序中唯一的元素,如class和static变量,能被所有线程共享。

2. 局部对象(Java不运行创建局部对象)

局部对象是C++中的概念,指不是通过new的方式创建的对象,存储于栈中,随函数结束而销毁。Java不允许创建局部变量,故Java对象均存储在堆上。因此,C++中不要反悔局部对象的指针和引用(更具体地说,不能返回超过栈顶的对象的指针和引用)。可以返回的对象包括:
1. 通过new分配的对象
2. static对象
3. 函数调用之前创建的局部对象

举以下代码为例,可以看到,test0生命周期结束后,局部变量自动释放。

#include "iostream"
using namespace std;

class Person
{
    public:
        Person(int a);
        ~Person();
        int getId();

    private:
        int id;
};

Person::Person(int a)
{
    id = a;
}

Person::~Person()
{
    cout << "释放对象: "<< id << endl;
}

int Person::getId()
{
    return id;
}

/*返回局部对象的指针*/
Person *test0()
{
    Person *p = &Person(0);
    return p;
}
/*返回new创建的对象的指针*/
Person *test1()
{
    Person *p = new Person(1);
    return p;
}
/*返回static对象的指针*/
Person *test2()
{
    static Person temp(2);//在静态区创建的对象,随程序一起结束
    Person *p = &temp;  
    return p;
}

void main()
{
    Person *p0, *p1, *p2;
    p0 = test0();
    p1 = test1();
    p2 = test2();
    cout << "p0 ID: " << p0->getId() << endl;
    cout << "p1 ID: " << p1->getId() << endl;
    cout << "p2 ID: " << p2->getId() << endl;
    delete p1;
    cout << "p1 ID: " << p1->getId() << endl;
    //delete p2;  报错,不能delete静态对象
    system("pause");
}

输出:

释放对象: 0
p0 ID: 17047552
p1 ID: 1
p2 ID: 2
释放对象: 1
p1 ID: -572662307

3 C++堆内存可以手动释放,栈和静态区不能手动释放

c++ 栈中和静态区建立的对象都不能delete,因为栈和静态区都不是程序员直接可操作存储区。而java不存在这些说法,因为java对象都是new出来的(String似乎是个例外)。
参见以下代码,Person类不变。

    void main()
    {
        Person p0(0);
        static Person p1(1);
        Person *p2 = new Person(2);

        delete &p0;  //报错,栈局部对象
        delete &p1;  //报错,静态区对象
        delete p2;   //正确,堆对象
    }

4 总结

  1. 无论是java还是c++, 函数可以返回new出来的对象(确切说,存储在堆上的对象)的引用(或c++指针)
  2. c++不可以返回局部对象的引用或指针

参考文献
Think in Java
C/C++堆栈指引
深入理解Java的栈与堆栈

注意
JAVA中的数据存储(堆及堆栈)中所说的栈中数据共享似乎有误。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值