💎一站式轻松地调用各大LLM模型接口,支持GPT4、智谱、星火、月之暗面及文生图 广告
### [数据存储](https://lingcoder.gitee.io/onjava8/#/book/03-Objects-Everywhere?id=%e6%95%b0%e6%8d%ae%e5%ad%98%e5%82%a8) 那么,程序在运行时是如何存储的呢?尤其是内存是怎么分配的。有5个不同的地方可以存储数据: 1. **寄存器**(Registers)最快的存储区域,位于 CPU 内部[^2](https://lingcoder.gitee.io/onjava8/#/%E5%A4%A7%E5%A4%9A%E6%95%B0%E5%BE%AE%E5%A4%84%E7%90%86%E5%99%A8%E8%8A%AF%E7%89%87%E9%83%BD%E6%9C%89%E9%A2%9D%E5%A4%96%E7%9A%84%E9%AB%98%E9%80%9F%E7%BC%93%E5%86%B2%E5%AD%98%E5%82%A8%E5%99%A8%EF%BC%8C%E4%BD%86%E8%BF%99%E6%98%AF%E6%8C%89%E7%85%A7%E4%BC%A0%E7%BB%9F%E5%AD%98%E5%82%A8%E5%99%A8%E8%80%8C%E4%B8%8D%E6%98%AF%E5%AF%84%E5%AD%98%E5%99%A8%E3%80%82)。然而,寄存器的数量十分有限,所以寄存器根据需求进行分配。我们对其没有直接的控制权,也无法在自己的程序里找到寄存器存在的踪迹(另一方面,C/C++ 允许开发者向编译器建议寄存器的分配)。 2. **栈内存**(Stack)存在于常规内存 RAM(随机访问存储器,Random Access Memory)区域中,可通过栈指针获得处理器的直接支持。栈指针下移分配内存,上移释放内存。这是一种仅次于寄存器的非常快速有效的分配存储方式。创建程序时,Java 系统必须知道栈内保存的所有项的生命周期。这种约束限制了程序的灵活性。因此,虽然在栈内存上存在一些 Java 数据(如对象引用),但 Java 对象本身的数据却是保存在堆内存的。 3. **堆内存**(Heap)这是一种通用的内存池(也在 RAM 区域),所有 Java 对象都存在于其中。与栈内存不同,编译器不需要知道对象必须在堆内存上停留多长时间。因此,用堆内存保存数据更具灵活性。创建一个对象时,只需用`new`命令实例化对象即可,当执行代码时,会自动在堆中进行内存分配。这种灵活性是有代价的:分配和清理堆内存要比栈内存需要更多的时间(如果可以用 Java 在栈内存上创建对象,就像在 C++ 中那样的话)。随着时间的推移,Java 的堆内存分配机制现在已经非常快,因此这不是一个值得关心的问题了。 4. **常量存储**(Constant storage)常量值通常直接放在程序代码中,因为它们永远不会改变。如需严格保护,可考虑将它们置于只读存储器 ROM (只读存储器,Read Only Memory)中[^3](https://lingcoder.gitee.io/onjava8/#/%E4%B8%80%E4%B8%AA%E4%BE%8B%E5%AD%90%E6%98%AF%E5%AD%97%E7%AC%A6%E4%B8%B2%E5%B8%B8%E9%87%8F%E6%B1%A0%E3%80%82%E6%89%80%E6%9C%89%E6%96%87%E5%AD%97%E5%AD%97%E7%AC%A6%E4%B8%B2%E5%92%8C%E5%AD%97%E7%AC%A6%E4%B8%B2%E5%80%BC%E5%B8%B8%E9%87%8F%E8%A1%A8%E8%BE%BE%E5%BC%8F%E9%83%BD%E4%BC%9A%E8%87%AA%E5%8A%A8%E6%94%BE%E5%85%A5%E7%89%B9%E6%AE%8A%E7%9A%84%E9%9D%99%E6%80%81%E5%AD%98%E5%82%A8%E4%B8%AD%E3%80%82)。 5. **非 RAM 存储**(Non-RAM storage)数据完全存在于程序之外,在程序未运行以及脱离程序控制后依然存在。两个主要的例子:(1)序列化对象:对象被转换为字节流,通常被发送到另一台机器;(2)持久化对象:对象被放置在磁盘上,即使程序终止,数据依然存在。这些存储的方式都是将对象转存于另一个介质中,并在需要时恢复成常规的、基于 RAM 的对象。Java 为轻量级持久化提供了支持。而诸如 JDBC 和 Hibernate 这些类库为使用数据库存储和检索对象信息提供了更复杂的支持。