有时当我尝试创建模糊的位图时,我会收到“空指针异常”。
发生在这段代码中(我最近开始捕获异常,所以至少它不会使应用程序崩溃):
try
{
using (Bitmap.Config config = Bitmap.Config.Rgb565) {
return Bitmap.CreateBitmap (blurredBitmap, width, height, config);
}
}
catch (Java.Lang.Exception exception)
{
Util.Log(exception.ToString());
}
有关我传入“CreateBitmap”方法的参数的详细信息,请参阅这些图片:
以下是扩展参数:
完全例外:
exception {Java.Lang.NullPointerException:类型异常 抛出'Java.Lang.NullPointerException'。在 System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() [0x0000b] in /Users/builder/data/lanes/2058/58099c53/source/mono/mcs/class/corlib/System.Runtime.ExceptionServices/ExceptionDispatchInfo.cs:61 在Android.Runtime.JNIEnv.CallStaticObjectMethod(IntPtr jclass, IntPtr jmethod,Android.Runtime.JValue * parms)[0x00064] in /Users/builder/data/lanes/2058/58099c53/source/monodroid/src/Mono.Android/src/Runtime/JNIEnv.g.cs:1301 在Android.Graphics.Bitmap.CreateBitmap(System.Int32 []颜色,Int32 width,Int32 height,Android.Graphics.Config config)[0x00088] in /Users/builder/data/lanes/2058/58099c53/source/monodroid/src/Mono.Android/platforms/android-22/src/generated/Android.Graphics.Bitmap.cs:735 在Psonar.Apps.Droid.PayPerPlay.StackBlur.GetBlurredBitmap (Android.Graphics.Bitmap原创,Int32半径)[0x00375] in d:\开发\ psonar \源\ Psonar.Apps \ Psonar.Apps.Droid \ Psonar.Apps.Droid.PayPerPlay \公用事业\ StackBlur.cs:123 ---托管异常堆栈跟踪结束--- java.lang.NullPointerException at android.graphics.Bitmap.createBitmap(Bitmap.java:687)at android.graphics.Bitmap.createBitmap(Bitmap.java:707)at dalvik.system.NativeStart.run(本机方法) } Java.Lang.NullPointerException
不确定这可能是Xamarin中的错误还是传递的参数错误。
答案 0 :(得分:2)
我收到了Xamarin团队成员之一的回复 - Jonathan Pryor:
NullPointerException来自Java代码:
在android.graphics.Bitmap.createBitmap(Bitmap.java:687) 在android.graphics.Bitmap.createBitmap(Bitmap.java:707) 在dalvik.system.NativeStart.run(原生方法)
快速浏览各种版本,Jelly Bean可能适合:
return nativeCreate(colors, offset, stride, width, height, config.nativeInt, false);
快速浏览周围的方法体,可以看出
config
未检查null-ness,因此如果传递null
,则会产生此结果 在NullPointerException中。但问题是你没有传递null:
using (Bitmap.Config config = Bitmap.Config.Rgb565) { return Bitmap.CreateBitmap (blurredBitmap, width, height, config); }
......或者是你?
我建议您删除
using
块:return Bitmap.CreateBitmap (blurredBitmap, width, height, Bitmap.Config.Rgb565);
这是我认为可能会发生的事情,但首先是一个题外话:
Xamarin.Android的核心深处有一个Java之间的映射 对象及其相应的C#包装器对象。构造函数 调用,Java.Lang.Object.GetObject()等将创建 映射; Java.lang.Object.Dispose()将删除映射。
这是对象身份的核心部分:当Java实例是 暴露于C#代码并创建了一个C#包装器,相同的 C#包装器 应该继续为该Java实例重用实例。
这样做的隐含结果是任何实例都是有效的 global ,因为如果有多个代码路径/ threads / etc.获取同一Java实例的JNI句柄,它们将获得相同的C#包装器。
这让我们回到了我的假设和你的代码块: Bitmap.Config是一个Java枚举,意味着每个成员都是一个Java对象。 此外,它们是全局值,因此每个线程都可以访问 那些成员,意思是C#Bitmap.Config.Rgb565实例 实际上是一个全局变量。
你是Dispose()的全局变量。
哪个“很好”,因为 next 时间Bitmap.Config.Rgb565是 访问时,将创建一个新的包装器。
但问题是,如果您有多个线程访问 Bitmap.Config.Rgb565在同一时间,每个都在尝试 Dispose()一个实例。在这一点上,它完全合情合理 两个线程可以引用相同的包装器实例,并且 因此,来自一个线程的Dispose()将对所使用的实例进行无效 另一个线程。
哪会导致
null
传递给Bitmap.createBitmap() 打电话,这正是你所观察到的。请尝试删除
using
块,看看这是否有用。
The whole thread is accessible here.
然后我问:
Jonathan Pryor - 为这个建议欢呼。我的问题是,如果我 删除using语句,会引入内存泄漏吗?含义 如果我停止处理新的配置实例?
他回答说:
这就是GC的用途!
(在这里插入咳嗽和笑声。)
我们可以狡辩一点。我认为它不是内存泄漏, 因为记忆力很好,众所周知;不断访问 Bitmap.Config.Rgb565将返回先前创建的实例, 不经常创建新实例。这样没有“泄漏”。
我会反而认为实例和底层的GREF是一个 “税”;它被“烧毁”,这是经营成本的一部分。虽然它 为了最大限度地降低这些成本会“很好”,删除是不切实际的 所有这些(例如我们通过.class_ref“失去”每个班级的GREF, 用于查找方法ID ...),至少不与当前相关 架构。
(我也想不出会导致的替代架构 不同的成本/“税收”。虽然我对允许有一些想法 在某些方面需要改进的地方,它们并不大。)
我建议不要担心Bitmap.Config.Rgb565和类似的问题 成员太多,除非/直到剖析器或GREF计数显示 否则。