13
14

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

[Unity+Android] C#からJavaのネイティブへのメソッド呼び出しを高速化してみる

Last updated at Posted at 2015-05-30

適当に、Javaのメソッドを呼び出してみる

以下は、UnityEngine.AndroidJavaObjectクラスとJavaのandroid.os.StatFsクラスを使って、100回連続で端末の空き容量を調べるスクリプトです。(普通こんなシチュエーションないですが・・・)

hoge.cs
	public int loopCount = 100;
    // 毎回 AndroidJavaObjectを生成 & 破棄
	public void CreateAndDispose ()
	{
		int blockSize = 0;
		int availableSize = 0;
		long startTime = DateTime.Now.Ticks;
		for (var i = 0; i < loopCount; ++i) {
			using (AndroidJavaObject statFs = new AndroidJavaObject( "android.os.StatFs", Application.persistentDataPath)) {
				blockSize = statFs.Call<int> ("getBlockSize");
				availableSize = statFs.Call<int> ("getAvailableBlocks");
			}
		}
		long endTime = DateTime.Now.Ticks;
		var duration = new TimeSpan (endTime - startTime);
		Debug.Log(string.Format ("Create Once {0} msec\n {1}", duration.TotalMilliseconds, (blockSize * availableSize)));
	}

    // 最初にAndroidJavaObjectを一個だけ生成 あとは使い回してCall
	public void CreateOnce ()
	{
		int blockSize = 0;
		int availableSize = 0;
		long startTime = DateTime.Now.Ticks;
		AndroidJavaObject statFs = new AndroidJavaObject ("android.os.StatFs", Application.persistentDataPath);
		for (var i = 0; i < loopCount; ++i) {
			blockSize = statFs.Call<int> ("getBlockSize");
			availableSize = statFs.Call<int> ("getAvailableBlocks");
		}
		statFs.Dispose ();
		long endTime = DateTime.Now.Ticks;
		var duration = new TimeSpan (endTime - startTime);
		Debug.Log(string.Format ("Create Once {0} msec\n {1}", duration.TotalMilliseconds, (blockSize * availableSize)));
	}

    // AndroidJavaObjectのメソッド呼び出しをキャッシュしてみた
	public void CreateTinyAndroidObject ()
	{
		int blockSize = 0;
		int availableSize = 0;
		long startTime = DateTime.Now.Ticks;
		TinyAndroidJavaObject statFs = new TinyAndroidJavaObject ("android.os.StatFs", Application.persistentDataPath);
		int getBlockSizeHash = statFs.LoadIntMethod ("getBlockSize");
		int getAvailableBlocksHash = statFs.LoadIntMethod ("getAvailableBlocks");
		for (var i = 0; i < loopCount; ++i) {
			blockSize = statFs.CallInt (getBlockSizeHash);
			availableSize = statFs.CallInt (getAvailableBlocksHash);
		}
		statFs.Dispose ();
		long endTime = DateTime.Now.Ticks;
		var duration = new TimeSpan (endTime - startTime);
		Debug.Log(string.Format ("Tiny {0} msec\n {1}", duration.TotalMilliseconds, (blockSize * availableSize)));
	}
TinyAndroidJavaObject.cs
using UnityEngine;
using System.Collections.Generic;
using System;

public class TinyAndroidJavaObject : AndroidJavaObject
{
	protected readonly Dictionary<int, IntPtr> _methodPtrCacheMap = new Dictionary<int, IntPtr> ();

	public TinyAndroidJavaObject (string className, params object[] args) : base(className, args) { }

    // 使いたいメソッドのMethodIDをキャッシュしておく
	public int LoadIntMethod (string methodName, params object[] paramSamples)
	{
        // オーバーロードを考えると、メソッド名だけじゃなく、引数の型もハッシュ計算に入れたほうが良さげ
		int methodNameHash = methodName.GetHashCode ();
		if (_methodPtrCacheMap.ContainsKey (methodNameHash)) {
			return 0;
		}
		IntPtr ptr = AndroidJNIHelper.GetMethodID<int> (m_jclass, methodName, paramSamples, false);
		if (ptr == default(IntPtr)) {
			return 0;
		}
		_methodPtrCacheMap [methodNameHash] = ptr;
		return methodNameHash;
	}

	public int CallInt (int methodNameHash, params object[] args)
	{
		if (_methodPtrCacheMap.ContainsKey (methodNameHash)) {
			if (args == null) {
				args = new object[0];
			}
			jvalue[] array = AndroidJNIHelper.CreateJNIArgArray (args);
			try {
				return AndroidJNI.CallIntMethod (m_jobject, _methodPtrCacheMap [methodNameHash], array);
			} finally {
				AndroidJNIHelper.DeleteJNIArgArray (args, array);
			}
		}
		return 0;
	}

	protected override void Dispose (bool disposing)
	{
		_methodPtrCacheMap.Clear ();
		base.Dispose (disposing);
	}
}

CreateAndDisposeとCreateOnceとCreateTinyAndroidObjectの実行時間の比較結果

環境は、2012年モデルのNexus7

  • CreateAndDispose(); => 35ms 前後
  • CreateOnce(); => 8ms 前後
  • CreateTinyAndroidObject(); => 1ms 前後

そこそこ早くできそう

重い重いと言われている、UnityからのネイティブAPI呼び出しだけど、頑張ればそれなりに軽減できるっぽい。
ただし、安全なのかはわかりませんけどね!

13
14
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
13
14

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?