3

I've been looking into whether anyone has found any documentation or figured out how to get object pooling to work with AoT compilation (which is required for iOS and WebGL for Unity) to work.

I've found this answer from Marc Gravell here, which describes how to get the factory to use your object pool, but this doesn't seem to work if you're using the AoT precompiler and calling code like this:

 public static T DeserializeProtoObject<T>(byte[] bytes)
 {
    using (MemoryStream m = new MemoryStream(bytes))
    {
        return (T)m_serializer.DeserializeWithLengthPrefix(m, null, typeof(T),ProtoBuf.PrefixStyle.Fixed32,0);
    }
 }

where m_serializer was created with the precompiler using code that looks like:

        var model = TypeModel.Create();
        model.Add(typeof(PlayerUpdate), true);
        model.AllowParseableTypes = true;
        model.AutoAddMissingTypes = true;
        model.Compile("IOGameProtoBufSerializer", "IOGameProtoBufSerializer.dll");

It looks like model has a SetDefaultFactory() function, but I'm not sure how to use it. Any tips from those in the know?

My next step is to download the source and dig through that.

Thanks for any help.

Edit: looks like I found the example source after downloading the full protobuf-net repo from here: https://github.com/mgravell/protobuf-net

For those who want to do the same thing here is the actual source showing an example of how to use the default constructor:

using Xunit;
using ProtoBuf;
using ProtoBuf.Meta;
using System;
using System.Threading;
using System.Reflection;
namespace Examples.Issues
{

    public class SO14532116
    {
        [Fact]
        public void Execute()
        {

            var model = TypeModel.Create();
            model.AutoCompile = false;
            model.SetDefaultFactory(typeof(SO14532116).GetMethod("ObjectMaker"));

            int oldCount = Count;
            Test(model, "Runtime");
            model.CompileInPlace();
            Test(model, "CompileInPlace");
            Test(model.Compile(), "CompileInPlace");
            model.Compile("SO14532116", "SO14532116.dll");
            PEVerify.AssertValid("SO14532116.dll");

            int newCount = Count;
            Assert.Equal(oldCount + 3, newCount);
        }

        [ProtoContract]
        public class Foo
        {
            [ProtoMember(1)]
            public int X {get;set;}

            public static Foo Create(int x = 0)
            {
                return new Foo(x);
            }

            public Foo(int x) { X = x; }
        }


        private void Test(TypeModel model, string p)
        {
            var obj = Foo.Create(123);

            int oldCount = Count;
            var clone = (Foo)model.DeepClone(obj);
            int newCount = Count;
            Assert.Equal(oldCount + 1, newCount);
            Assert.Equal(123, clone.X);
        }

        private static int count;
        public static int Count
        {
            get { return Interlocked.CompareExchange(ref count, 0, 0); } 
        }
        public static object ObjectMaker(Type type)
        {
            object obj;
            if(type == typeof(Foo))
            {
                obj = Foo.Create();
            } else {
                obj = Activator.CreateInstance(type);
            }
            Interlocked.Increment(ref count);
            return obj;

        }
    }
}
bererton
  • 41
  • 3
  • OK, so after downloading the full repo, I was able to find the example code that Mark mentioned in the other post for using the default factory. Unfortunately I can't post it here in a comment. But just clone the git repo from here: https://github.com/mgravell/protobuf-net and then go to Examples -> Issues -> SO14532116.cs – bererton Feb 21 '18 at 20:15

1 Answers1

1

The precompiler is ... awkward, and virtually impossible to support - it pretty much doesn't exist in 2.3, and a key deliverable of the next milestone is to replace it entirely with build-time code-generation, something that 2.3 started by rewriting the schema tooling. Long term: this should be a much better option!

An example of how to use SetDefaultFactory can be seen here. I can set no expectation on how this will work with the precompiler - if it works: great!

Marc Gravell
  • 1,026,079
  • 266
  • 2,566
  • 2,900
  • Great, thanks Marc. Also thanks for the link to the source. The older posts' link was busted and google didn't help me. I look forward to using the new stuff in 2.3 when it's available. For now I'm trying to stop memory allocations for a multiplayer game server and related clients that are using protobuf-net. When the garbage collector runs it causes a noticeable performance hiccup unfortunately. – bererton Feb 21 '18 at 20:24