搞懂内存大小及计算机类的内存占用

Ubuntu 64位系统下编译32位C++可执行文件

步骤1:命令行安装这个支持多编译的包

sudo apt-get install gcc-multilib g++-multilib

步骤2:g++编译的时候加上 -m32 参数

g++ -m32 heheda.cpp -o heheda

 运行:./heheda 时就是32位的了

(一)内存大小

1.空类大小

#include 
using namespace std;

class A{

};

int main() {
    std::cout<< sizeof(A) <

【总结】c++要求每个实例在内存中都有独一无二的地址。空类也会被实例化,所以编译器会给空类隐含的添加一个字节,这样空类实例化之后就有了独一无二的地址了。所以空类的sizeof为1。

2.包含1到N个虚函数的类内存大小

#include 
using namespace std;

class A{
public:
    virtual void Test();
};

int main() {
    std::cout<< sizeof(A) <

64位系统下,8字节;32位系统下,4字节

#include 
using namespace std;

class A{
public:
    virtual void Test();
    virtual void TestA();
};

int main() {
    std::cout<< sizeof(A) <

64位系统下,8字节;32位系统下,4字节

【总结】C++ 类中有虚函数的时候有一个指向虚函数的指针(vptr),在32位系统分配指针大小为4字节。无论多少个虚函数,只有这一个指针,4字节。

3.内存对齐

#include 
using namespace std;

class A{
public:
    virtual void Test();
    virtual void TestA();
private:
    int age; 
    bool sex;
};

int main() {
    std::cout<< sizeof(A) <

64位系统下,16字节;32位系统下,12字节

① 以32位系统来解释:int 占4字节,bool占一字节,补齐3字节,虚函数的指针(vptr)的大小为4字节,所以为12字节

#include 
using namespace std;

class A{
public:
    virtual void Test();
    virtual void TestA();
private:
    int age; 
    bool sex;
    bool bChild;
};

int main() {
    std::cout<< sizeof(A) <

64位系统下,16字节;32位系统下,12字节

① 以32位系统来解释:int 占4字节,bool sex占一字节,bool bChild占一字节,sex和bChild紧挨着放一起,补齐2字节,虚函数的指针(vptr)的大小为4字节,所以为12字节

class A{
public:
    virtual void Test();
    virtual void TestA();
private:
    bool bChild;
    int age; 
    bool sex;
};

int main() {
    std::cout<< sizeof(A) <

64位系统下,24字节;32位系统下,16字节

① 以32位系统来解释:bool bChild占一字节补齐3字节,int 占4字节,bool sex占一字节补齐3字节,虚函数的指针(vptr)的大小为4字节,所以为16字节

4.有继承的虚函数类的大小

【例子1】:

class CBase 
{ 
public: 
    CBase(void); 
    virtual ~CBase(void); 
private: 
    int  a; 
    char *p; 
}; 

 64位系统下,24字节;32位系统下,12字节 

① 以32位系统来解释:在32位系统分配指针大小为4字节。虚函数的指针(vptr)的大小为4字节,int 占4字节,char类型的指针p的大小为4字节,所以为12字节

② 以64位系统来解释:在64位系统分配指针大小为8字节。虚函数的指针(vptr)的大小为8字节,int 占4字节,补齐4字节,char类型的指针p的大小为8字节,所以为24字节

class CChild : public CBase 
{ 
public: 
    CChild(void); 
    ~CChild(void); 
    virtual void test();
private: 
    int b; 
}; 

 64位系统下,32字节;32位系统下,16字节 

【注意】子类的大小是本身成员变量的大小加上父类的大小。

① 以32位系统来解释:父类的大小为12字节,int 占4字节,所以为16字节

② 以64位系统来解释:父类的大小为24字节,int 占4字节,所以为32字节(往往被调整到系统的整数倍。)

【例子2】:

class A {};   
 
class B{};   
 
class C:public A{
    virtual void fun()=0;
};             
  
class D:public B,public C{}; 

  64位系统下,A占1字节,B占1字节,C占8字节,D占8字节;

  32位系统下,A占1字节,B占1字节,C占4字节,D占4字节;

class A {};   
 
class B{
private:
    bool c;
    int a;
    bool b;
};     
 
class C:public A{
    virtual void fun()=0;
};           
  
class D:public B,public C{};   

64位系统下,A占1字节,B占12字节,C占8字节,D占24字节;

32位系统下,A占1字节,B占12字节,C占4字节,D占16字节;

class A {};   
 
class B{
private:
    int a;
    bool b;
    bool c;
};     
 
class C:public A{
    virtual void fun()=0;
};             
  
class D:public B,public C{}; 

64位系统下,A占1字节,B占8字节,C占8字节,D占16字节;

32位系统下,A占1字节,B占8字节,C占4字节,D占12字节; 

二、测试

【测试一】

#include 
using namespace std;
// ====== 测试一 ======
class Test {
private:
    int n;
    char c;
    short s;
};

int main() {
    Test t21;
    cout << sizeof(t21) << endl;//x64:8  x86:8
    return 0;
}

64位系统下,8字节

32位系统下,8字节

【测试二】

#include 
#include 
using namespace std;
// ====== 测试二 ======
class Test {
private:
    int n;
    char c;
    short s;
    static int a;
};

int main() {
    Test t21;
    cout << sizeof(t21) << endl;//x64:8  x86:8
    return 0;
}

64位系统下,8字节

32位系统下,8字节

【总结】静态变量不计算在类所占内存的大小。

【原因】

① static修饰的静态变量:不占用内容

② 由于类的静态成员变量编译时被分配到静态/全局区,静态成员变量是属于类的,所有对象共用一份,不计入类的内存空间。

【测试三】

#include 
#include 
using namespace std;
// ====== 测试三 ======
class Test {
public:
	//构造函数
    Test() {

    }
	//普通成员
    int func0() {
        return n;
    }
	//友元函数
    friend int func1();
	//常成员函数
    int func2() const {
        return s;
    }
	//内联函数
    inline void func3() {
        cout << "inline function" << endl;
    }
	//静态成员函数
    static void func4() {
        cout << "static function" << endl;
    }
	//析构函数
    ~Test() {

    }

private:
    int n;
    char c;
    short s;
    static int a;
};

int func1() {
    Test t;
    return t.c;
}

int main() {
    Test t22;
    cout << sizeof(t22) << endl;//x64:8  x86:8
    return 0;
}

64位系统下,8字节

32位系统下,8字节

【总结】由于C++中成员函数和非成员函数都是存放在代码区的,类中一般成员函数、友元函数,内联函数还是静态成员函数都不计入类的内存空间

【原因】类内部的成员函数:
① 普通函数:不占用内存。

② C++编译系统中,数据和函数是分开存放的(函数放在代码区;数据主要放在栈区或堆区,静态/全局区以及文字常量区也有),实例化不同对象时,只给数据分配空间,各个对象调用函数时都都跳转到(内联函数例外)找到函数在代码区的入口执行,可以节省拷贝多份代码的空间

③ 数据主要放在栈区或堆区,有可能是堆,也有可能是栈。这取决于实例化对象的方式:

A a = new A(); //堆

int a; //栈

④ 内联函数(声明和定义都要加inline)也是存放在代码区。inline与成员函数是否占用对象的存储空间无关

【测试四】

#include 
#include 
using namespace std;
// ====== 测试四 ======
class Test {
public:
    Test() {

    }

    int func0() {
        return n;
    }

    friend int func1();

    int func2() const {
        return s;
    }

    inline void func3() {
        cout << "inline function" << endl;
    }

    static void func4() {
        cout << "static function" << endl;
    }
	//虚函数,需要一个虚函数指针的开销
    virtual void func5() {
        cout << "virtual function1" << endl;
    }

    virtual void func6() {
        cout << "virtual function2" << endl;
    }

    ~Test() {

    }

private:
    int n;
    char c;
    short s;
    static int a;
};

int func1() {
    Test t;
    return t.c;
}


int main() {
    Test t22;
    cout << sizeof(t22) << endl;//x64:16  x86:12
    return 0;
}

64位系统下,16字节

32位系统下,12字节

【总结】由于出现了虚函数,故类要维护一个指向虚函数表的指针。虚函数指针和虚基类指针也属于数据部分。

原因】类内部的成员函数:
⑤ 虚函数:要占用4个字节(32位系统)或8个字节(64位系统),用来指定虚函数的虚拟函数表的入口地址。所以一个类的虚函数所占用的地址是不变的,和虚函数的个数是没有关系的

三、总结(参考这篇博客)

C++中类所占的内存大小以及成员函数的存储位置_为什么成员函数不占用类的空间_SOC罗三炮的博客-CSDN博客icon-default.png?t=N6B9https://blog.csdn.net/luolaihua2018/article/details/110736211

你可能感兴趣的:(c++,类的内存大小,内存大小)