这确实让我感到惊讶,我在玩Java Unsafe。基本上我正在测试的是
Allocate unsafe memory -> free the memory -> Write to the freed memory
当我访问已释放的内存时,我曾期望看到某种分段错误错误,但令人惊讶的是,未引发任何错误/异常。
我的代码是:
protected static final Unsafe UNSAFE;
static {
try {
Field field = Unsafe.class.getDeclaredField("theUnsafe");
field.setAccessible(true);
UNSAFE = (Unsafe) field.get(null);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
@Test
public void test() {
long ptr = UNSAFE.allocateMemory(1000);
UNSAFE.freeMemory(ptr);
UNSAFE.putOrderedLong(null, ptr, 100L);
}
我的问题是,如果是这样,那为什么我们在Unsafe中需要freeMemory()
函数呢?真的是为了什么?
答案 0 :(得分:2)
仅当您读取未分配页面的地址或写入只读或未分配页面的内存时,您才会收到信号。
当您分配较小的内存区域时,它将从本机内存池中获取该内存,释放时通常不会将其释放回操作系统。
如果释放内存,然后再分配,则该内存可用于其他用途。继续使用旧地址可能会导致损坏。
答案 1 :(得分:1)
这可能已完全关闭,但无论如何我都会发布。
在我看来,这类似于它在C中的工作方式(如@ John3136建议)。查看“官方”文档(http://www.docjar.com/html/api/sun/misc/Unsafe.java.html),很显然,您分配的内存是本机内存。这意味着它在JVM内存中,但在OS自身分配给JVM的堆中。
当OS分配了一块内存时,它会为此内存分配一个特定的地址范围,并且(除了静态内存和代码等其他几件事之外)堆从底部开始增长,而堆栈从顶部开始增长地址空间(希望这是熟悉的)。因此,如果在堆中分配了内存,并且再次引用它,那么您就不可能超出操作系统分配的范围。实际上,我敢肯定,如果您尝试使用UNSAFE.putOrderedLong(null, ptr+4, 100L)
的计算机,它仍然可以正常工作。现在,确切存储在其中的内容甚至对于OS本身都是一个谜,但是由于UNSAFE
的运行水平如此之低,因此绝对有可能。