秒懂地址与指针的关系

本文介绍了计算机内存的地址概念,包括如何通过地址线产生内存地址,探讨了内存单元的大小对内存空间的影响。通过实例讲解了如何查看数据的地址,并深入阐述了指针变量的定义、类型以及解引用操作。最后讨论了不同系统下指针变量所占用的字节数。

计算机的内存被划分为一个一个小的空间,每一个空间都被编上了编号。这种编号被称为地址。

现在摆在我们面前有两个问题

  1. 如何给编号,给什么样的编号呢?即如何编址?
  2. 一个空间要给划分多大呢?

如何产生地址

我们在日常中经常说,我这个电脑是32位的,我这个电脑是64位的。

这里的32位和64位分别指的是,有32根地址线和64根地址线。

地址线就像电线,一旦通电里面的电流就有正负电之分。用1代表正电,0代表负数。

以32位为例,会产生如下可能

00000000000000000000000000000000
00000000000000000000000000000001
00000000000000000000000000000010
...
01111111111111111111111111111111
10000000000000000000000000000000
...
11111111111111111111111111111111

总计产生232个二进制序列。也就是232个编号。这些编号就是内存中的地址。

一个内存单元多大

如果一个内存单元是1bit,那么之前说32位系统。会有232个编号,也就是232个内存单元。232个比特位用计算器算一下为4294967296bit。4294967296bit经过换算是0.5GB内存空间。可是我们买电脑都是8G内存起步啊?一个内存空间是1bit大小,还是不太合适。

那如果一个内存单元是1byte呢?1byte=8bit,比上一个猜想大了八倍,4GB内存空间,这样结果就合理多了。

而事实上一个内存地址空间也确实占用1byte。

查看数据的地址

&叫取地址符,能查看地址。

int main()
{
    int a = 10;
    printf("%p\n",&a);
    return 0;
}

运行结果
在这里插入图片描述
这个008FFE9C就是地址换算成二进制是1000 1111 1111 1110 1001 1100

地址的存放

有一种变量是用来存放地址。这种变量叫做指针变量。

定义指针变量,比如定义整型a的指针变量。

int a =10;
int* p = &a;

p是个指针变量,p = &a,那p的类型是什么呢?是int*。

就如同定义整型变量a时要写int一样。要让p存放整型变量a的地址,p的类型要写成int*,即p是个指针变量它的类型是int*。

可以验证一下

int main()
{
    int a = 10;
    int* p = &a;
    printf("%p\n",&a);
    printf("%p\n", p);

    return 0;
}

运行结果
在这里插入图片描述
现在p中已经存放了a的地址。我们把a的地址存放到p中,就是为了以后通过地址找到a。那么怎么找呢?

* ———— 解引用操作符

这个星号就是解引用操作符,将它加到p的前面,就是对p进行解引用操作,找到p存储的地址所对应的对像a。

不妨做个测试,既然*p就是对p进行解引用操作找到它存储的地址所指的对像a。

那么对*p赋值20,看看a的结果改变没有。

int main()
{
    int a = 10;
    int* p = &a;
    *p = 20;
    printf("a = %d\n", a);

    return 0;
}

运行结果
在这里插入图片描述

指针变量的大小

我们知道之前创建整型变量a占用四个字节,那指针变量p多大?占几个字节?

这个问题应该这样思考,指针变量中存放的是地址,地址是如何产生的?地址其实就是32位的二进制序列。32位等于4字节。所以在32位系统中指针变量占4字节。

那么如果是64位机器,是有64个地址线的,每根地址线都能产生0,1,那就是64位0与1组成的二进制序列,如果要存起来就是64个比特位的空间也就是8个字节。所以64位系统中指针变量占8字节。

<think>嗯,用户之前问过常量池和运行时常量池的关系,现在又问了方法区和元空间的关系。看来他对Java内存区域特别是方法区这部分比较感兴趣,或者在学习过程中遇到了相关的问题。 首先,我需要确认用户的问题点。方法区和元空间这两个概念在Java的不同版本中有变化,尤其是在JDK 8的时候,元空间取代了永久代。用户可能在学习时发现资料中提到的方法区和元空间有所混淆,想要明确两者的关系和区别。 用户之前的问题是关于常量池的存储位置,涉及到方法区,所以现在这个问题可能是对之前内容的延伸。需要理清方法区是JVM规范中的概念,而永久代和元空间是具体的实现。不同版本的JDK实现方式不同,比如JDK7之前方法区由永久代实现,而JDK8之后改为元空间,使用本地内存。 接下来,要考虑用户的背景。可能他正在准备面试或者学习JVM内存模型,遇到了这两个术语,需要明确它们的关系。这时候需要从规范和实现两个层面来解释,方法区是规范,元空间是实现方式之一,取代了永久代。 还要注意用户可能的误解,比如认为方法区和元空间是同一个东西,或者不清楚为何要做这样的改变。需要解释永久代的问题,比如容易OOM,调优困难,而元空间使用本地内存,可以自动扩展,减少OOM风险,提高性能。 另外,用户可能想知道元空间的具体细节,比如存储的内容、内存管理方式(Metaspace和Compressed Class Space),以及相关的JVM参数。这些内容在回答中需要简要提及,但不宜过于深入,以免让用户感到混乱。 最后,总结两者的关系,强调方法区是逻辑概念,元空间是具体实现,帮助用户形成清晰的理解。同时,联系用户之前的问题,说明运行时常量池现在位于元空间,而字符串常量池在堆中,避免混淆。</think>### **用「仓库改造」比喻方法区元空间的关系**: --- #### **1. 方法区(Method Area)——JVM规范中的「仓库蓝图」** - **是什么**:JVM规范定义的**逻辑概念**,用于存储类信息、常量池、静态变量等元数据。 - **核心特点**: - **规范层面**:所有JVM实现必须要有方法区,但**不规定具体实现方式**(如同建筑蓝图只要求有仓库,不限制建材)。 - **存储内容**: - 类元数据(类名、方法字节码、字段描述等) - 运行时常量池 - 静态变量(JDK7后静态变量移到堆中) --- #### **2. 元空间(Metaspace)——JDK8+的「现代化仓库」** - **是什么**:**JDK8及之后**对方法区的**具体实现**,取代了JDK7之前的**永久代(PermGen)**。 - **关键变革**: | **对比项** | **永久代(JDK7-)** | **元空间(JDK8+)** | |----------------|----------------------------------|--------------------------------| | **物理位置** | 在JVM堆内存中划分区域 | 使用**本地内存(Native Memory)** | | **内存管理** | 受JVM堆大小限制,需手动调优(-XX:PermSize) | **自动扩展**,默认无上限 | | **OOM风险** | 易出现`java.lang.OutOfMemoryError: PermGen space` | 更少OOM(除非物理内存耗尽) | | **垃圾回收** | Full GC时回收 | 特定条件下元数据可被卸载 | --- ### **3. 二者关系:规范 vs 实现** - **方法区是接口**:如同「仓库必须能存货物」的抽象要求。 - **元空间是具体实现**:如同用「钢结构+智能管理系统」建造的真实仓库。 - **历史演变**: - JDK7-:方法区 = 永久代(堆内实现) - JDK8+:方法区 = 元空间(本地内存实现 + 压缩类指针优化) --- #### **4. 元空间技术细节** - **两个子空间**: - **Metaspace**:存Klass结构(类的元数据) - **Compressed Class Space**:存压缩后的类指针(默认1G,通过`-XX:CompressedClassSpaceSize`调整) - **重要参数**: ```bash -XX:MetaspaceSize=128m # 初始大小 -XX:MaxMetaspaceSize=512m # 限制最大大小(防止本地内存耗尽) ``` --- ### **5. 为什么要用元空间替代永久代?** - **根本矛盾**:永久代在堆内,类元数据动态加载的特性不匹配。 - **三大痛点**: 1. **调优困难**:需预测永久代大小,容易OOM 2. **GC低效**:Full GC时回收元数据,导致STW时间长 3. **兼容性差**:HotSpot其他JVM(如JRockit)的方法区实现难以统一 --- ### **6. 一句话总结** - **方法区是JVM规范里的“仓库需求文档”,元空间是JDK8+的“仓库施工方案”**。 - 从永久代到元空间的升级,本质是让类元数据存储摆脱堆内存束缚,拥抱更灵活的本地内存管理!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值