从规格我们知道
每个进程的虚拟地址空间都分为多个分区。在x86 32位Windows上,0x00000000 - 0x0000FFFF(包括)的分区称为NULL指针分配分区。预留此分区是为了帮助程序员捕获NULL指针分配。如果aprocess中的某个线程试图读取或写入该分区中的内存地址,则会引发访问violoation。
因此,如果我们创建一个具有64 * 1024 + 1字节字段的假设对象,例如
struct Foo {
byte field1;
byte field2;
...
byte field65536;
byte SomeUnexpectedData;
}* Bar = 0;
Bar->SomeUnexpectedData = 0;
所以这里我们使用了单位化的空指针,那么环境如何避免呢?我们不能创建大于64K的对象或什么?
C#test
using System;
using System.Reflection;
using System.Reflection.Emit;
namespace BigObjTest
{
class Program
{
static void Main()
{
var type = GetObjType();
var obj = Activator.CreateInstance(type);
Console.WriteLine(obj);
}
private static Type GetObjType()
{
var typebuilder = GetTypeBuilder();
for (int i = 0; i <= 65535; i++)
{
typebuilder.DefineField("_" + ("b" + i), typeof (byte), FieldAttributes.Private);
}
return typebuilder.CreateType();
}
private static TypeBuilder GetTypeBuilder()
{
const string typeSignature = "MyDynamicType";
var an = new AssemblyName(typeSignature);
AssemblyBuilder assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(an, AssemblyBuilderAccess.Run);
ModuleBuilder moduleBuilder = assemblyBuilder.DefineDynamicModule("MainModule");
TypeBuilder tb = moduleBuilder.DefineType(typeSignature
, TypeAttributes.Public |
TypeAttributes.Class |
TypeAttributes.AutoClass |
TypeAttributes.AnsiClass |
TypeAttributes.BeforeFieldInit |
TypeAttributes.AutoLayout
, null);
return tb;
}
}
}
奇怪的是,如果对象大于64K,CLR会抛出异常,但如果写入65534而不是65535,它将正常工作。因此,我认为在具有强类型系统的托管语言中是不可能的。
答案 0 :(得分:2)
访问空指针会导致未定义的行为。无法保证系统检测和/或处理此问题。使用受保护的内存页面来捕获大多数错误似乎仍然是一个合理的应用程序。
你当然可以拥有超过64kB的物体。但是,你可能不会发现使用它们的一些微不足道的错误。
答案 1 :(得分:0)
我认为你错过了分区的重点。如果指针分配不正确,那就是:
int *p = NULL;
*p = 4;
然后系统可以捕获它,而不是让它做一些可怕的事情。 64K限制意味着它可以捕获高达64K的值。这是因为:
p = 56678455;
可能是有效的&#39;地址区域但仍然是错误的分配。它无法检查所有内容。