Big memory overhead

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • Mikolas

    Big memory overhead

    Hello,

    I'm writing an app running both under .NET and Compact Frameword. I need to allocate lot of little mem blocks. They form a n-ary tree, i.e. pointing at each other. The mem alloc by the program is just prepostrous - it's about 4times more than I esimate these objects should take. On PC it's not such a big deal but on the PPC 32MB device it's quite a problem. Does anyone know it there's something to do about it? Or why it is happening?

    tnhx
  • Jon Skeet [C# MVP]

    #2
    Re: Big memory overhead

    Mikolas <Mikolas@discus sions.microsoft .com> wrote:[color=blue]
    > I'm writing an app running both under .NET and Compact Frameword. I
    > need to allocate lot of little mem blocks. They form a n-ary tree,
    > i.e. pointing at each other. The mem alloc by the program is just
    > prepostrous - it's about 4times more than I esimate these objects
    > should take. On PC it's not such a big deal but on the PPC 32MB
    > device it's quite a problem. Does anyone know it there's something to
    > do about it? Or why it is happening?[/color]

    Could you give an example of the kind of object you're allocating, and
    how you're estimating the required memory usage?

    --
    Jon Skeet - <skeet@pobox.co m>
    Pobox has been discontinued as a separate service, and all existing customers moved to the Fastmail platform.

    If replying to the group, please do not mail me too

    Comment

    • Jon Skeet [C# MVP]

      #3
      Re: Big memory overhead

      Mikolas <Mikolas@discus sions.microsoft .com> wrote:[color=blue]
      > For example one of the classes these data members :
      > {
      > uint sectionID; // my estimate 4B
      > string sectionName; // dunno, but hope not much more than 2*length
      >
      > ArrayList subsections;//my estimate 10B + capacity*4
      > ArrayList machines;//my estimate 10B + capacity*4
      > ArrayList graphicObjs;//my estimate 10B + capacity*4
      > IDMap graphicObjsToSu bsections;//my estimate 10B + capacity*4
      > IDMap graphicObjsToMa chines;//my estimate 10B + capacity*4[/color]

      Okay. For one thing, there's 8 bytes overhead for the class itself.
      Then for each reference, there's a 4 byte overhead. string takes
      12 bytes + (length+1)*2 rounded up to a multiple of 4
      Each ArrayList is going to be 24 + capacity*4 (I think). IDMap will
      depend on the implementation, obviously.

      So, how "out" your estimates are really depend on the size of strings
      and the capacity of your ArrayLists. Could you give a sample object and
      what size you're seeing, and we'll see if we can explain it?

      --
      Jon Skeet - <skeet@pobox.co m>
      Pobox has been discontinued as a separate service, and all existing customers moved to the Fastmail platform.

      If replying to the group, please do not mail me too

      Comment

      • Jim H

        #4
        Re: Big memory overhead

        Keep in mind that strings in C# are wide character strings, so there's you
        minimum 2*length. The you need to add in data members like Length (which
        I'm sure is not recaclulated everytime the Length property is accessed) and
        the internal member to stroe the address of the string, plus a minimum of 2
        bytes per character. Even in C++ string objects can be heavy.

        The ArrayLists I don't know about. I guess it depends on the memory
        management of the object and how it was coded(performan ce vs. size) Again
        keep in mind internal members such as size, reference, and synconizer
        objects. Also what are the lists storing? Capacity * 4 makes me assume
        refernce types but if they are value types or structs it can be larger.

        ..02
        jim

        "Mikolas" <Mikolas@discus sions.microsoft .com> wrote in message
        news:FE7F4BB6-81F5-4A95-8AE9-28A2F0D7077F@mi crosoft.com...[color=blue]
        > For example one of the classes these data members :
        > {
        > uint sectionID; // my estimate 4B
        > string sectionName; // dunno, but hope not much more than 2*length
        >
        > ArrayList subsections;//my estimate 10B + capacity*4
        > ArrayList machines;//my estimate 10B + capacity*4
        > ArrayList graphicObjs;//my estimate 10B + capacity*4
        > IDMap graphicObjsToSu bsections;//my estimate 10B + capacity*4
        > IDMap graphicObjsToMa chines;//my estimate 10B + capacity*4
        >
        > mikolas
        >
        > "Jon Skeet [C# MVP]" wrote:
        >[color=green]
        > > Mikolas <Mikolas@discus sions.microsoft .com> wrote:[color=darkred]
        > > > I'm writing an app running both under .NET and Compact Frameword. I
        > > > need to allocate lot of little mem blocks. They form a n-ary tree,
        > > > i.e. pointing at each other. The mem alloc by the program is just
        > > > prepostrous - it's about 4times more than I esimate these objects
        > > > should take. On PC it's not such a big deal but on the PPC 32MB
        > > > device it's quite a problem. Does anyone know it there's something to
        > > > do about it? Or why it is happening?[/color]
        > >
        > > Could you give an example of the kind of object you're allocating, and
        > > how you're estimating the required memory usage?
        > >
        > > --
        > > Jon Skeet - <skeet@pobox.co m>
        > > http://www.pobox.com/~skeet
        > > If replying to the group, please do not mail me too
        > >[/color][/color]


        Comment

        • Jon Skeet [C# MVP]

          #5
          Re: Big memory overhead

          Jim H <nospam@jimsacc ount.com> wrote:[color=blue]
          > Keep in mind that strings in C# are wide character strings, so there's you
          > minimum 2*length. The you need to add in data members like Length (which
          > I'm sure is not recaclulated everytime the Length property is accessed) and
          > the internal member to stroe the address of the string, plus a minimum of 2
          > bytes per character. Even in C++ string objects can be heavy.[/color]

          There's no internal member to store the address of the string - strings
          are special in that the size of the string object itself varies
          according to the size. The data for the string is within the string
          object itself (unlike Java, where String contains a char array
          reference).
          [color=blue]
          > The ArrayLists I don't know about. I guess it depends on the memory
          > management of the object and how it was coded(performan ce vs. size) Again
          > keep in mind internal members such as size, reference, and synconizer
          > objects. Also what are the lists storing? Capacity * 4 makes me assume
          > refernce types but if they are value types or structs it can be larger.[/color]

          No, the size of the ArrayList's data array will always be capacity*4
          because it *can* only store references - value types end up getting
          boxed (assuming we're not talking about v2 with generics).

          --
          Jon Skeet - <skeet@pobox.co m>
          Pobox has been discontinued as a separate service, and all existing customers moved to the Fastmail platform.

          If replying to the group, please do not mail me too

          Comment

          • Jon Skeet [C# MVP]

            #6
            Re: Big memory overhead

            Mikolas <Mikolas@discus sions.microsoft .com> wrote:[color=blue][color=green]
            > > So, how "out" your estimates are really depend on the size of strings
            > > and the capacity of your ArrayLists. Could you give a sample object and
            > > what size you're seeing, and we'll see if we can explain it?[/color]
            >
            > I created a sample binary tree with 2^17 nodes like mentioned above,
            > when created the the mem usage in Task list rises by 56MB. This could
            > also be because there's still plenty of free mem. On PPC though, when
            > I create 2^16 nodes the mem usage rises by 13MB and there's almost
            > nothing left(from 32MB).[/color]

            But what is the contents of the ArrayLists and strings in that case?
            That's only 488 bytes per node, which doesn't sound very much to me -
            you don't need to have very large ArrayLists to see that.
            [color=blue]
            > You can easily get similar results from
            > <code>
            > class MyTree
            > {
            > string name;
            > MyTree left, right;
            > MyTree(string name)
            > {
            > this.name = name;
            > }
            >
            > public static MyTree CreateSample(st ring name, int depth)
            > {
            > if (depth <= 0)
            > return null;
            >
            > MyTree mt = new MyTree(name);
            >
            > mt.left = CreateSample(na me + "0", depth - 1);
            > mt.right = CreateSample(na me + "1", depth - 1);
            >
            > return mt;
            > }
            >
            >
            > }
            > MyTree mt;
            > private void button1_Click(o bject sender, System.EventArg s e)
            > {
            > this.mt = MyTree.CreateSa mple("root", 20);
            >
            > }
            > </code>[/color]

            And what results did you get from that? (I haven't got time to run it
            myself right now.)

            --
            Jon Skeet - <skeet@pobox.co m>
            Pobox has been discontinued as a separate service, and all existing customers moved to the Fastmail platform.

            If replying to the group, please do not mail me too

            Comment

            • Jim H

              #7
              Re: Big memory overhead

              Thanks. I guess I shouldn't post assumptions.
              Sorry,
              jim

              "Jon Skeet [C# MVP]" <skeet@pobox.co m> wrote in message
              news:MPG.1b6b44 e9df35e5c298af8 c@msnews.micros oft.com...[color=blue]
              > Jim H <nospam@jimsacc ount.com> wrote:[color=green]
              > > Keep in mind that strings in C# are wide character strings, so there's[/color][/color]
              you[color=blue][color=green]
              > > minimum 2*length. The you need to add in data members like Length[/color][/color]
              (which[color=blue][color=green]
              > > I'm sure is not recaclulated everytime the Length property is accessed)[/color][/color]
              and[color=blue][color=green]
              > > the internal member to stroe the address of the string, plus a minimum[/color][/color]
              of 2[color=blue][color=green]
              > > bytes per character. Even in C++ string objects can be heavy.[/color]
              >
              > There's no internal member to store the address of the string - strings
              > are special in that the size of the string object itself varies
              > according to the size. The data for the string is within the string
              > object itself (unlike Java, where String contains a char array
              > reference).
              >[color=green]
              > > The ArrayLists I don't know about. I guess it depends on the memory
              > > management of the object and how it was coded(performan ce vs. size)[/color][/color]
              Again[color=blue][color=green]
              > > keep in mind internal members such as size, reference, and synconizer
              > > objects. Also what are the lists storing? Capacity * 4 makes me assume
              > > refernce types but if they are value types or structs it can be larger.[/color]
              >
              > No, the size of the ArrayList's data array will always be capacity*4
              > because it *can* only store references - value types end up getting
              > boxed (assuming we're not talking about v2 with generics).
              >
              > --
              > Jon Skeet - <skeet@pobox.co m>
              > http://www.pobox.com/~skeet
              > If replying to the group, please do not mail me too[/color]


              Comment

              • Willy Denoyette [MVP]

                #8
                Re: Big memory overhead


                "Jon Skeet [C# MVP]" <skeet@pobox.co m> wrote in message
                news:MPG.1b6b44 e9df35e5c298af8 c@msnews.micros oft.com...[color=blue]
                > Jim H <nospam@jimsacc ount.com> wrote:[/color]
                [color=blue]
                > No, the size of the ArrayList's data array will always be capacity*4
                > because it *can* only store references - value types end up getting
                > boxed (assuming we're not talking about v2 with generics).
                >[/color]

                Jon,

                The exact size of the ArrayList's data array (Object[]) is actualy; 16 +
                capacity*4.

                Or:
                0 Int32 Sync#
                4 Int32 MT ptr. (method table ptr. Object[])
                8 Int32 Component size
                12 Int32 MT ptr. (Method table pointer of element types
                (Object))
                16 Int32 elem1
                20 Int32 elem2
                .....

                Willy.


                Comment

                • Willy Denoyette [MVP]

                  #9
                  Re: Big memory overhead


                  Did you start with an initial size for the ArrayList?
                  If you don't, your first AL (actually the items Object[]) will have an
                  initial size of 16 + 4*4bytes, when this array get full the CLR will expand
                  this array using a simple algorithm ((actual number of elements * component
                  size) * 2), so yes, it grows exponential.
                  See where this goes to?

                  Willy.



                  "Mikolas" <Mikolas@discus sions.microsoft .com> wrote in message
                  news:D590F66F-AD2A-4D4F-8996-1D8FB7CADE0D@mi crosoft.com...[color=blue]
                  >
                  >
                  > "Jon Skeet [C# MVP]" wrote:
                  >[color=green]
                  >> Mikolas <Mikolas@discus sions.microsoft .com> wrote:[color=darkred]
                  >> > For example one of the classes these data members :
                  >> > {
                  >> > uint sectionID; // my estimate 4B
                  >> > string sectionName; // dunno, but hope not much more than 2*length
                  >> >
                  >> > ArrayList subsections;//my estimate 10B + capacity*4
                  >> > ArrayList machines;//my estimate 10B + capacity*4
                  >> > ArrayList graphicObjs;//my estimate 10B + capacity*4
                  >> > IDMap graphicObjsToSu bsections;//my estimate 10B + capacity*4
                  >> > IDMap graphicObjsToMa chines;//my estimate 10B + capacity*4[/color]
                  >>
                  >> Okay. For one thing, there's 8 bytes overhead for the class itself.
                  >> Then for each reference, there's a 4 byte overhead. string takes
                  >> 12 bytes + (length+1)*2 rounded up to a multiple of 4
                  >> Each ArrayList is going to be 24 + capacity*4 (I think). IDMap will
                  >> depend on the implementation, obviously.
                  >>
                  >> So, how "out" your estimates are really depend on the size of strings
                  >> and the capacity of your ArrayLists. Could you give a sample object and
                  >> what size you're seeing, and we'll see if we can explain it?
                  >>[/color]
                  >
                  > I created a sample binary tree with 2^17 nodes like mentioned above, when
                  > created the the mem usage in Task list rises by 56MB. This could also be
                  > because there's still plenty of free mem.
                  > On PPC though, when I create 2^16 nodes the mem usage rises by 13MB and
                  > there's almost nothing left(from 32MB).
                  >
                  > You can easily get similar results from
                  > <code>
                  > class MyTree
                  > {
                  > string name;
                  > MyTree left, right;
                  > MyTree(string name)
                  > {
                  > this.name = name;
                  > }
                  >
                  > public static MyTree CreateSample(st ring name, int depth)
                  > {
                  > if (depth <= 0)
                  > return null;
                  >
                  > MyTree mt = new MyTree(name);
                  >
                  > mt.left = CreateSample(na me + "0", depth - 1);
                  > mt.right = CreateSample(na me + "1", depth - 1);
                  >
                  > return mt;
                  > }
                  >
                  >
                  > }
                  > MyTree mt;
                  > private void button1_Click(o bject sender, System.EventArg s e)
                  > {
                  > this.mt = MyTree.CreateSa mple("root", 20);
                  >
                  > }
                  > </code>
                  >
                  >
                  >
                  >[color=green]
                  >> --
                  >> Jon Skeet - <skeet@pobox.co m>
                  >> http://www.pobox.com/~skeet
                  >> If replying to the group, please do not mail me too
                  >>[/color][/color]


                  Comment

                  • Jon Skeet [C# MVP]

                    #10
                    Re: Big memory overhead

                    Willy Denoyette [MVP] <willy.denoyett e@pandora.be> wrote:[color=blue][color=green]
                    > > No, the size of the ArrayList's data array will always be capacity*4
                    > > because it *can* only store references - value types end up getting
                    > > boxed (assuming we're not talking about v2 with generics).[/color]
                    >
                    > The exact size of the ArrayList's data array (Object[]) is actualy; 16 +
                    > capacity*4.
                    >
                    > Or:
                    > 0 Int32 Sync#
                    > 4 Int32 MT ptr. (method table ptr. Object[])
                    > 8 Int32 Component size
                    > 12 Int32 MT ptr. (Method table pointer of element types
                    > (Object))
                    > 16 Int32 elem1
                    > 20 Int32 elem2
                    > ....[/color]

                    Apologies, yes, I forgot about the normal overhead, length and type.

                    --
                    Jon Skeet - <skeet@pobox.co m>
                    Pobox has been discontinued as a separate service, and all existing customers moved to the Fastmail platform.

                    If replying to the group, please do not mail me too

                    Comment

                    • Mikolas

                      #11
                      Re: Big memory overhead



                      "Willy Denoyette [MVP]" wrote:
                      [color=blue]
                      >
                      > "Jon Skeet [C# MVP]" <skeet@pobox.co m> wrote in message
                      > news:MPG.1b6b44 e9df35e5c298af8 c@msnews.micros oft.com...[color=green]
                      > > Jim H <nospam@jimsacc ount.com> wrote:[/color]
                      >[color=green]
                      > > No, the size of the ArrayList's data array will always be capacity*4
                      > > because it *can* only store references - value types end up getting
                      > > boxed (assuming we're not talking about v2 with generics).
                      > >[/color]
                      >
                      > Jon,
                      >
                      > The exact size of the ArrayList's data array (Object[]) is actualy; 16 +
                      > capacity*4.
                      >
                      > Or:
                      > 0 Int32 Sync#
                      > 4 Int32 MT ptr. (method table ptr. Object[])
                      > 8 Int32 Component size
                      > 12 Int32 MT ptr. (Method table pointer of element types
                      > (Object))
                      > 16 Int32 elem1
                      > 20 Int32 elem2
                      > .....
                      >
                      > Willy.[/color]


                      Is there any tool how to do "sizeof" then?

                      thnx[color=blue]
                      >
                      >
                      >[/color]

                      Comment

                      • Jon Skeet [C# MVP]

                        #12
                        Re: Big memory overhead

                        Mikolas <Mikolas@discus sions.microsoft .com> wrote:[color=blue]
                        > Is there any tool how to do "sizeof" then?[/color]

                        No, not really. I find the best way to judge is to create a lot of
                        objects and look at the memory difference. Change the number of objects
                        to make sure it's linear, otherwise you could get phased by overheads
                        etc.

                        --
                        Jon Skeet - <skeet@pobox.co m>
                        Pobox has been discontinued as a separate service, and all existing customers moved to the Fastmail platform.

                        If replying to the group, please do not mail me too

                        Comment

                        • Willy Denoyette [MVP]

                          #13
                          Re: Big memory overhead

                          A tool? Yes, the native debugger check

                          and this article http://msdn.microsoft.com/msdnmag/is.../06/Bugslayer/
                          to get you started.


                          Willy.

                          "Mikolas" <Mikolas@discus sions.microsoft .com> wrote in message
                          news:90A80331-4A15-4A53-9B2F-0B70DDE36509@mi crosoft.com...[color=blue]
                          >
                          >
                          > "Willy Denoyette [MVP]" wrote:
                          >[color=green]
                          >>
                          >> "Jon Skeet [C# MVP]" <skeet@pobox.co m> wrote in message
                          >> news:MPG.1b6b44 e9df35e5c298af8 c@msnews.micros oft.com...[color=darkred]
                          >> > Jim H <nospam@jimsacc ount.com> wrote:[/color]
                          >>[color=darkred]
                          >> > No, the size of the ArrayList's data array will always be capacity*4
                          >> > because it *can* only store references - value types end up getting
                          >> > boxed (assuming we're not talking about v2 with generics).
                          >> >[/color]
                          >>
                          >> Jon,
                          >>
                          >> The exact size of the ArrayList's data array (Object[]) is actualy; 16 +
                          >> capacity*4.
                          >>
                          >> Or:
                          >> 0 Int32 Sync#
                          >> 4 Int32 MT ptr. (method table ptr. Object[])
                          >> 8 Int32 Component size
                          >> 12 Int32 MT ptr. (Method table pointer of element types
                          >> (Object))
                          >> 16 Int32 elem1
                          >> 20 Int32 elem2
                          >> .....
                          >>
                          >> Willy.[/color]
                          >
                          >
                          > Is there any tool how to do "sizeof" then?
                          >
                          > thnx[color=green]
                          >>
                          >>
                          >>[/color][/color]


                          Comment

                          Working...