Code to find the size of an object

J

Jon Jagger

I was thinking about how you can only use sizeof to find the size of an
unmanaged type. I started to wonder if there was a way to find the size of a
managed object and came up with the following. It's not guaranteed behaviour
but it seems to work. Doesn't lose verifiability either. Enjoy.
Cheers
Jon Jagger



namespace JSL
{
using System.Runtime.InteropServices;

public delegate object Creator();

public static class Size
{
public static int Of(Creator f)
{
Union a = new Union();
a.u2.o = f();
Union b = new Union();
b.u2.o = f();

return System.Math.Abs(a.u1.value - b.u1.value);
}

private struct U1
{
public int value;
}

private struct U2
{
public object o;
}

[StructLayout(LayoutKind.Explicit)]
private struct Union
{
[FieldOffset(0)] public U1 u1;
[FieldOffset(0)] public U2 u2;
}
}
}

namespace Example
{
using JSL;
using System;

class C
{
public C()
{
a = b = c = d = 42;
}

private int a,b,c,d;
}

class App
{
static void Main()
{
Creator c = delegate { return new C(); };
Console.WriteLine(Size.Of(c));
}
}
}
 
W

Willy Denoyette [MVP]

Jon,
Your code only works if all members are primitive types, try adding a string
and check the result.
It also assumes that a and b are laid-out sequentially which is a wrong
assumption when multiple threads are creating objects, and is neither
guaranteed by the CLR.

Willy.
 
J

Jon Jagger

Still works for me. As for assumptions - I specifically said it was _not_
guaranteed behaviour but thanks for being explicit about what the reasons
are.
Cheers
Jon Jagger


that a,b would always be layed
a,b being layed out sequentially and threading...these are exactly the
reasons it's not guaranteed behaviour (which I mentioned).

Willy Denoyette said:
Jon,
Your code only works if all members are primitive types, try adding a string
and check the result.
It also assumes that a and b are laid-out sequentially which is a wrong
assumption when multiple threads are creating objects, and is neither
guaranteed by the CLR.

Willy.

Jon Jagger said:
I was thinking about how you can only use sizeof to find the size of an
unmanaged type. I started to wonder if there was a way to find the size
of
a
managed object and came up with the following. It's not guaranteed behaviour
but it seems to work. Doesn't lose verifiability either. Enjoy.
Cheers
Jon Jagger



namespace JSL
{
using System.Runtime.InteropServices;

public delegate object Creator();

public static class Size
{
public static int Of(Creator f)
{
Union a = new Union();
a.u2.o = f();
Union b = new Union();
b.u2.o = f();

return System.Math.Abs(a.u1.value - b.u1.value);
}

private struct U1
{
public int value;
}

private struct U2
{
public object o;
}

[StructLayout(LayoutKind.Explicit)]
private struct Union
{
[FieldOffset(0)] public U1 u1;
[FieldOffset(0)] public U2 u2;
}
}
}

namespace Example
{
using JSL;
using System;

class C
{
public C()
{
a = b = c = d = 42;
}

private int a,b,c,d;
}

class App
{
static void Main()
{
Creator c = delegate { return new C(); };
Console.WriteLine(Size.Of(c));
}
}
}
 
W

Willy Denoyette [MVP]

No sure how you are considering the result as valid?
Just modify your code as follows (and run in sequence):

1. Add a unitialized string member to the class, now Size.Of will return 28
(which is wrong).
2. Assign a value to the string in the constructor, lets say string s =
"Hello", the return value will be 56(which is correct, but this is not
guaranteed to be consistent).
3. Assign a value to s in your Of method ..
public static int Of(Creator f)
{
Union a = new Union();
a.u2.o = f();
(a.u2.o as Example.C).s = "Hello Hello";
.....
Size.Of will return 56 (which is wrong, and not guaranteed to be
consistent).

Hope you got the picture ;-)
Willy.


Jon Jagger said:
Still works for me. As for assumptions - I specifically said it was _not_
guaranteed behaviour but thanks for being explicit about what the reasons
are.
Cheers
Jon Jagger


that a,b would always be layed
a,b being layed out sequentially and threading...these are exactly the
reasons it's not guaranteed behaviour (which I mentioned).

Willy Denoyette said:
Jon,
Your code only works if all members are primitive types, try adding a string
and check the result.
It also assumes that a and b are laid-out sequentially which is a wrong
assumption when multiple threads are creating objects, and is neither
guaranteed by the CLR.

Willy.
size
of
a
managed object and came up with the following. It's not guaranteed behaviour
but it seems to work. Doesn't lose verifiability either. Enjoy.
Cheers
Jon Jagger



namespace JSL
{
using System.Runtime.InteropServices;

public delegate object Creator();

public static class Size
{
public static int Of(Creator f)
{
Union a = new Union();
a.u2.o = f();
Union b = new Union();
b.u2.o = f();

return System.Math.Abs(a.u1.value - b.u1.value);
}

private struct U1
{
public int value;
}

private struct U2
{
public object o;
}

[StructLayout(LayoutKind.Explicit)]
private struct Union
{
[FieldOffset(0)] public U1 u1;
[FieldOffset(0)] public U2 u2;
}
}
}

namespace Example
{
using JSL;
using System;

class C
{
public C()
{
a = b = c = d = 42;
}

private int a,b,c,d;
}

class App
{
static void Main()
{
Creator c = delegate { return new C(); };
Console.WriteLine(Size.Of(c));
}
}
}
 
J

Jon Jagger

Yup I get 28. I'm not saying this is valid or invalid. Only that I get 28. I
agree that logically I would except it to be 24 (because that is 4 more than
20). But I don't. I get 28. So clearly my logic is incomplete. If I add 2
reference fields the answer is 32. Perhaps there is a one-time hit of 4
bytes if you use any reference type fields? I don't know. I'm simply
exploring. As for adding...
(a.u2.o as Example.C).s = "Hello Hello";
to the code...Well you've changed the code. So don't change it ;-)
Cheers
Jon Jagger

Willy Denoyette said:
No sure how you are considering the result as valid?
Just modify your code as follows (and run in sequence):

1. Add a unitialized string member to the class, now Size.Of will return 28
(which is wrong).
2. Assign a value to the string in the constructor, lets say string s =
"Hello", the return value will be 56(which is correct, but this is not
guaranteed to be consistent).
3. Assign a value to s in your Of method ..
public static int Of(Creator f)
{
Union a = new Union();
a.u2.o = f();
(a.u2.o as Example.C).s = "Hello Hello";
....
Size.Of will return 56 (which is wrong, and not guaranteed to be
consistent).

Hope you got the picture ;-)
Willy.


Jon Jagger said:
Still works for me. As for assumptions - I specifically said it was _not_
guaranteed behaviour but thanks for being explicit about what the reasons
are.
Cheers
Jon Jagger


that a,b would always be layed
a,b being layed out sequentially and threading...these are exactly the
reasons it's not guaranteed behaviour (which I mentioned).

Willy Denoyette said:
Jon,
Your code only works if all members are primitive types, try adding a string
and check the result.
It also assumes that a and b are laid-out sequentially which is a wrong
assumption when multiple threads are creating objects, and is neither
guaranteed by the CLR.

Willy.


I was thinking about how you can only use sizeof to find the size of an
unmanaged type. I started to wonder if there was a way to find the
size
of
a
managed object and came up with the following. It's not guaranteed
behaviour
but it seems to work. Doesn't lose verifiability either. Enjoy.
Cheers
Jon Jagger



namespace JSL
{
using System.Runtime.InteropServices;

public delegate object Creator();

public static class Size
{
public static int Of(Creator f)
{
Union a = new Union();
a.u2.o = f();
Union b = new Union();
b.u2.o = f();

return System.Math.Abs(a.u1.value - b.u1.value);
}

private struct U1
{
public int value;
}

private struct U2
{
public object o;
}

[StructLayout(LayoutKind.Explicit)]
private struct Union
{
[FieldOffset(0)] public U1 u1;
[FieldOffset(0)] public U2 u2;
}
}
}

namespace Example
{
using JSL;
using System;

class C
{
public C()
{
a = b = c = d = 42;
}

private int a,b,c,d;
}

class App
{
static void Main()
{
Creator c = delegate { return new C(); };
Console.WriteLine(Size.Of(c));
}
}
}
 
W

Willy Denoyette [MVP]

Jon,
Considering the title of this posting, I (wrongly ?) assumed your code was
trying to show us how to find the correct size of an object, which in fact
it does only for a particular case.
I'm trying to show you (and the NG readers) is that there is no managed way
get the size of an arbitrary object.

Note that 24 is the correct size of the object (CLR 1.0 and 1.1) containing
4 int's (4 bytes sync. block info, 4 bytes method/vtable pointer, 4 * 4
bytes (int data members)).
The value of 28 is wrong when adding a string is wrong, because it doesn't
account for the string object when not initialized in the constructor (only
4 bytes are added for the string reference).

Willy.


Jon Jagger said:
Yup I get 28. I'm not saying this is valid or invalid. Only that I get 28. I
agree that logically I would except it to be 24 (because that is 4 more than
20). But I don't. I get 28. So clearly my logic is incomplete. If I add 2
reference fields the answer is 32. Perhaps there is a one-time hit of 4
bytes if you use any reference type fields? I don't know. I'm simply
exploring. As for adding...
(a.u2.o as Example.C).s = "Hello Hello";
to the code...Well you've changed the code. So don't change it ;-)
Cheers
Jon Jagger

Willy Denoyette said:
No sure how you are considering the result as valid?
Just modify your code as follows (and run in sequence):

1. Add a unitialized string member to the class, now Size.Of will return 28
(which is wrong).
2. Assign a value to the string in the constructor, lets say string s =
"Hello", the return value will be 56(which is correct, but this is not
guaranteed to be consistent).
3. Assign a value to s in your Of method ..
public static int Of(Creator f)
{
Union a = new Union();
a.u2.o = f();
(a.u2.o as Example.C).s = "Hello Hello";
....
Size.Of will return 56 (which is wrong, and not guaranteed to be
consistent).

Hope you got the picture ;-)
Willy.


Jon Jagger said:
Still works for me. As for assumptions - I specifically said it was _not_
guaranteed behaviour but thanks for being explicit about what the reasons
are.
Cheers
Jon Jagger


that a,b would always be layed
a,b being layed out sequentially and threading...these are exactly the
reasons it's not guaranteed behaviour (which I mentioned).

Jon,
Your code only works if all members are primitive types, try adding a
string
and check the result.
It also assumes that a and b are laid-out sequentially which is a wrong
assumption when multiple threads are creating objects, and is neither
guaranteed by the CLR.

Willy.


I was thinking about how you can only use sizeof to find the size
of
an
unmanaged type. I started to wonder if there was a way to find the size
of
a
managed object and came up with the following. It's not guaranteed
behaviour
but it seems to work. Doesn't lose verifiability either. Enjoy.
Cheers
Jon Jagger



namespace JSL
{
using System.Runtime.InteropServices;

public delegate object Creator();

public static class Size
{
public static int Of(Creator f)
{
Union a = new Union();
a.u2.o = f();
Union b = new Union();
b.u2.o = f();

return System.Math.Abs(a.u1.value - b.u1.value);
}

private struct U1
{
public int value;
}

private struct U2
{
public object o;
}

[StructLayout(LayoutKind.Explicit)]
private struct Union
{
[FieldOffset(0)] public U1 u1;
[FieldOffset(0)] public U2 u2;
}
}
}

namespace Example
{
using JSL;
using System;

class C
{
public C()
{
a = b = c = d = 42;
}

private int a,b,c,d;
}

class App
{
static void Main()
{
Creator c = delegate { return new C(); };
Console.WriteLine(Size.Of(c));
}
}
}
 
J

Jon Jagger

Willy Denoyette said:
Jon,
Considering the title of this posting, I (wrongly ?) assumed your code was
trying to show us how to find the correct size of an object,

Yes. I should have added a ? to the end of the subject line to match the
"not guaranteed behaviour" content. Apologies.
I'm trying to show you (and the NG readers) is that there is no managed way
get the size of an arbitrary object.

Agreed.
Cheers
Jon Jagger
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top