Android 服务导致内存问题
Android service causes memory problems
我的 Android 应用程序遇到了一些问题。在应用程序中,我有一个很长的 运行 任务,用于在用户成功登录后将用户数据从 Azure 服务器同步到本地 SQL。因此我设计了一个服务,它与 activity 启动时,通知用户任务需要多长时间。
应用程序必须从在线数据库复制到本地 SQLlite 的数据非常大,这导致内存峰值非常高,因为 AzureService 和 SqlService 必须请求相当大的数据列表。它从 +- 30mb 到 60mb ram。完成所有这些后,负责同步的 activity 将停止服务并启动 SecondActivity。
我的问题是,即使在 FirstActivity(处理同步)已经杀死所有东西(连接、服务、activity 本身……),内存仍然没有不要加入 SecondActivity。我已经尝试了不同的技巧让它下降(在监视器中打出“导致 gc”,打开其他需要内存的应用程序)但它似乎不起作用。我不知道我可能在 FirstActivity 中泄漏了什么,导致内存在 SecondActivity 中保持高位,据我所知调试,所有需要销毁的东西都会被销毁。 我做错了什么?
FirstActivity:
[Activity (Label = "Dvit.Apps.MemoryManager", MainLauncher = true, Icon = "@drawable/icon")]
public class FirstActivity : Activity
{
BirdyService _service;
IServiceConnection _connection;
TextView _serviceOutput;
Boolean _isBound = false;
public FirstActivity ()
{
_connection = new SyncServiceConnection (this);
}
protected override void OnCreate (Bundle bundle)
{
base.OnCreate (bundle);
// Set our view from the "main" layout resource
SetContentView (Resource.Layout.Main);
Button btnStartService = FindViewById<Button> (Resource.Id.myButton);
Button NextPage = new Button (this);
_serviceOutput = FindViewById<TextView> (Resource.Id.txtServiceOutput);
NextPage.LayoutParameters = new ViewGroup.LayoutParams (WindowManagerLayoutParams.MatchParent, 100);
NextPage.Gravity = GravityFlags.CenterHorizontal;
NextPage.Text = "Next Page";
NextPage.Click += (object sender, EventArgs e) => {
UnboundService();
this.Finish();
StartActivity(typeof(SecondActivity));
};
(btnStartService.Parent as LinearLayout).AddView (NextPage);
btnStartService.Click += delegate {
BindService ();
Intent syncLoginInfoIntent = new Intent (this, typeof(BirdyService));
syncLoginInfoIntent.PutExtra ("commandType", "LoginSync");
StartService (syncLoginInfoIntent);
};
}
void BindService ()
{
Console.WriteLine ("Bind service");
base.BindService (new Intent (this, typeof(BirdyService)), _connection, Bind.AutoCreate);
_isBound = true;
}
void UnboundService ()
{
Console.WriteLine ("Unbinding service");
if (_isBound) {
((SyncServiceConnection)_connection).OnDisconnect ();
base.UnbindService (_connection);
_isBound = false;
}
}
void HandleSyncFeedback (object sender, BirdyService.SyncProgressEventArgs e)
{
this.RunOnUiThread(() =>{_serviceOutput.Text += "\n" + e.Extra;});
}
protected override void OnDestroy ()
{
base.OnDestroy ();
Console.WriteLine ("FirstActivity Destroyed!");
_connection = null;
_serviceOutput = null;
}
class SyncServiceConnection: Java.Lang.Object, IServiceConnection
{
FirstActivity _self;
public SyncServiceConnection (FirstActivity self)
{
_self = self;
}
public void OnServiceConnected (ComponentName className, IBinder service)
{
Console.WriteLine ("~~CONNECTING SERVICE!!!~~");
_self._service = ((BirdyService.SyncBinder)service).Service;
_self._service.SyncProgressEvent += _self.HandleSyncFeedback;
}
public void OnDisconnect ()
{
Console.WriteLine ("~~DISCONECTING SERVICE!!!~~");
if (_self._service != null) {
_self._service.SyncProgressEvent -= _self.HandleSyncFeedback;
_self._service = null;
}
}
public void OnServiceDisconnected (ComponentName className)
{
}
}
}
SecondActivity:
[Activity (Label = "Dvit.Apps.MemoryManager", Icon = "@drawable/icon")]
public class SecondActivity : Activity
{
int count = 1;
protected override void OnCreate (Bundle bundle)
{
base.OnCreate (bundle);
// Set our view from the "main" layout resource
SetContentView (Resource.Layout.Main);
// Get our button from the layout resource,
// and attach an event to it
}
protected override void OnDestroy ()
{
base.OnDestroy ();
Console.WriteLine ("SecondActivity Destroyed!");
}
}
服务:
[Service (Enabled = true)]
public class BirdyService:Service
{
IAzureService _azureSvc;
ISqlService _sqlSvc;
ISyncService _syncSvc;
IGlobalSettings _settings;
AndroidSqlteConnection _connection;
#region Service 'IsSyncing?' Checkers
private Boolean _syncLoginSync = false;
public Boolean IsServiceSyncing {
get {
if (_syncLoginSync == true)
return true;
else
return false;
}
}
#endregion
public class SyncProgressEventArgs:EventArgs
{
public SyncProgressEventArgs ()
{
this.Progress = 0;
this.IsCompleted = false;
}
public bool IsCompleted {
get;
set;
}
public string Extra{ get; set; }
public Int16 Progress {
get;
set;
}
}
public event EventHandler<SyncProgressEventArgs> SyncProgressEvent;
#region Binder => communication between starting activity & service
private IBinder binder;
public class SyncBinder:Binder
{
BirdyService _service;
public SyncBinder (BirdyService service)
{
_service = service;
}
public BirdyService Service {
get{ return _service; }
}
}
public override IBinder OnBind (global::Android.Content.Intent intent)
{
return binder;
}
#endregion
public BirdyService () : base ()
{
binder = new SyncBinder (this);
}
public override void OnCreate ()
{
base.OnCreate ();
var appContext = this.ApplicationContext as MemoryManagerApplication;
_settings = appContext.GlobalSettings;
_azureSvc = new AzureService (new MobileServiceClient (_settings.AzureMobileServiceUrl, _settings.AzureMobileServicePassword));
_connection = new AndroidSqlteConnection ();
_sqlSvc = new SqlService (_connection);
_syncSvc = new SyncService (_azureSvc, appContext.WebApiClient, _sqlSvc, _settings);
}
public override StartCommandResult OnStartCommand (global::Android.Content.Intent intent, StartCommandFlags flags, int startId)
{
if (intent != null) {
var command = intent.GetStringExtra ("commandType");
var keepAlive = intent.GetBooleanExtra ("keepAlive", false);
Console.WriteLine ("~~>SERVICE TASK RECEIVED COMMMANDNAME: " + command + "<~~");
switch (command) {
case "LoginSync":
{
LoginSync (intent, keepAlive);
}
break;
}
}
return StartCommandResult.Sticky;
}
#region LoginSync
private void LoginSync (global::Android.Content.Intent intent, bool keepAlive = false)
{
new Task (async () => {
try {
var progressEventArg = new SyncProgressEventArgs ();
_syncLoginSync = true;
_settings.IsSyncingOrganisations = true;
progressEventArg.Extra = "Fetching master data...";
progressEventArg.Progress = 10;
if (SyncProgressEvent != null)
this.SyncProgressEvent (null, progressEventArg);
await _syncSvc.SyncMasterData (true);
var requestUserInfoFragment = await Authenticate (progressEventArg);
_settings.IsSyncingOrganisations = false;
progressEventArg.Extra = "Completed!";
progressEventArg.Progress = 100;
progressEventArg.IsCompleted = true;
if (SyncProgressEvent != null)
SyncProgressEvent (requestUserInfoFragment, progressEventArg);
_syncLoginSync = false;
if (!IsServiceSyncing && !keepAlive)
this.StopSelf ();
} catch (Exception ex) {
_syncLoginSync = false;
//_Logger.Trace (ex.Message);
_settings.IsSyncingOrganisations = false;
if (!IsServiceSyncing)
this.StopSelf ();
throw;
}
}).Start ();
}
async Task<Boolean> Authenticate (SyncProgressEventArgs args)
{
try {
args.Extra = "Fetching user...";
args.Progress = 30;
if (this.SyncProgressEvent != null)
this.SyncProgressEvent (null, args);
Account account = await _azureSvc.AccountByGoogleId (_settings.LoginUserId);
if (account != null) {
var party = await _azureSvc.GetItemById<Party> (account.PartyId);
args.Extra = "User found, initializing user data ...";
args.Progress = 50;
if (this.SyncProgressEvent != null)
this.SyncProgressEvent (null, args);
_sqlSvc.Insert<Party> (party);
_sqlSvc.Insert<Account> (account);
args.Extra = "User found, fetching organisation data...";
args.Progress = 50;
if (this.SyncProgressEvent != null)
this.SyncProgressEvent (null, args);
//Fetch organisations
await _syncSvc.SyncPartyInitData (party.Id, true, true);
//Fetch appointments & orders
args.Extra = "Organisation data completed, fetching party data...";
args.Progress = 80;
if (this.SyncProgressEvent != null)
this.SyncProgressEvent (null, args);
await _syncSvc.SyncPartyDetailData (party.Id);
//do not request user info
return false;
} else {
//FILL IN ACCOUNT
account = new Account ();
Party party = new Party ();
party.Id = Guid.NewGuid ().ToString ();
account.Id = Guid.NewGuid ().ToString ();
account.IdentityProvider = _settings.LoginPlatform;
account.IdentityToken = _settings.LoginUserId;
account.PartyId = party.Id;
account.InfoProvider = _settings.UserInfo.RawData;
account.LoginName = _settings.LoginUserId;
//FILL IN PARTY
bool requestUserInfoFragment = false;
if (_settings.UserInfo != null) {
if (!String.IsNullOrWhiteSpace (_settings.UserInfo.FirstName)) {
party.FirstName = _settings.UserInfo.FirstName;
} else
requestUserInfoFragment = true;
if (!String.IsNullOrWhiteSpace (_settings.UserInfo.LastName)) {
party.LastName = _settings.UserInfo.LastName;
} else
requestUserInfoFragment = true;
if (!String.IsNullOrWhiteSpace (_settings.UserInfo.Email)) {
party.Email = _settings.UserInfo.Email;
} else
requestUserInfoFragment = true;
}
party.LocalIsNew = true;
account.LocalIsNew = true;
_sqlSvc.Insert<Party> (party);
_sqlSvc.Insert<Account> (account);
if (!requestUserInfoFragment) {
args.Extra = "Adding new users to the server";
args.Progress = 80;
if (this.SyncProgressEvent != null)
this.SyncProgressEvent (null, args);
await _syncSvc.SyncAllFromType<Party> ();
await _syncSvc.SyncAllFromType<Account> ();
}
//ELSE sync in newuserfragment
return requestUserInfoFragment;
}
} catch (Exception ex) {
throw;
}
}
#endregion
public override void OnDestroy ()
{
base.OnDestroy ();
Console.WriteLine ("Destroying BirdyService");
_connection.Close ();
_connection = null;
_azureSvc = null;
_sqlSvc = null;
_syncSvc = null;
_settings = null;
}
}
首先,打开严格模式以检测 activity 泄漏,首先将其添加到应用程序的 OnCreate activity:
StrictMode.SetVmPolicy (new StrictMode.VmPolicy.Builder ().DetectAll ().PenaltyLog ().Build ());
每当检测到超过 1 个 activity 类型实例时,这将向 logcat 发出警告。它看起来像这样:
[StrictMode] class md5962cfe7bc03e689322450e055e633b77.FirstActivity; instances=2; limit=1
[StrictMode] android.os.StrictMode$InstanceCountViolation: class md5962cfe7bc03e689322450e055e633b77.FirstActivity; instances=2; limit=1
[StrictMode] at android.os.StrictMode.setClassInstanceLimit(StrictMode.java:1)
接下来是为您的 activity 切断对等对象连接:
protected override void OnDestroy ()
{
base.OnDestroy ();
base.Dispose ();
GC.Collect (GC.MaxGeneration);
}
base.Dispose ()
中断了 C# 对象和 Java Vm 对象之间的对等对象连接。 http://developer.xamarin.com/guides/android/advanced_topics/garbage_collection/#Disposing_of_Peer_instances
一般来说,这应该足以修复样品的泄漏。您还可以更进一步,将 Activity 中派生自 Java.Lang.Object 的所有对象置为空。例如:
protected override void OnDestroy ()
{
button.Dispose ();
button = null;
base.OnDestroy ();
base.Dispose ();
GC.Collect (GC.MaxGeneration);
}
你的问题的核心是你不知道哪些内容仍在被引用,以及哪些内容正在引用它。
使用 Android Studio 中的工具追踪内存分配位置应该很简单。 Memory Profiling 101 介绍如何使用内存监视器、分配跟踪器和堆查看器来查找具体问题。
真的,这些工具可以让您非常清楚地了解内存的去向。我将从那里开始,窥探你的第二个 activity 仍然掌握的内容。
我的 Android 应用程序遇到了一些问题。在应用程序中,我有一个很长的 运行 任务,用于在用户成功登录后将用户数据从 Azure 服务器同步到本地 SQL。因此我设计了一个服务,它与 activity 启动时,通知用户任务需要多长时间。
应用程序必须从在线数据库复制到本地 SQLlite 的数据非常大,这导致内存峰值非常高,因为 AzureService 和 SqlService 必须请求相当大的数据列表。它从 +- 30mb 到 60mb ram。完成所有这些后,负责同步的 activity 将停止服务并启动 SecondActivity。
我的问题是,即使在 FirstActivity(处理同步)已经杀死所有东西(连接、服务、activity 本身……),内存仍然没有不要加入 SecondActivity。我已经尝试了不同的技巧让它下降(在监视器中打出“导致 gc”,打开其他需要内存的应用程序)但它似乎不起作用。我不知道我可能在 FirstActivity 中泄漏了什么,导致内存在 SecondActivity 中保持高位,据我所知调试,所有需要销毁的东西都会被销毁。 我做错了什么?
FirstActivity:
[Activity (Label = "Dvit.Apps.MemoryManager", MainLauncher = true, Icon = "@drawable/icon")]
public class FirstActivity : Activity
{
BirdyService _service;
IServiceConnection _connection;
TextView _serviceOutput;
Boolean _isBound = false;
public FirstActivity ()
{
_connection = new SyncServiceConnection (this);
}
protected override void OnCreate (Bundle bundle)
{
base.OnCreate (bundle);
// Set our view from the "main" layout resource
SetContentView (Resource.Layout.Main);
Button btnStartService = FindViewById<Button> (Resource.Id.myButton);
Button NextPage = new Button (this);
_serviceOutput = FindViewById<TextView> (Resource.Id.txtServiceOutput);
NextPage.LayoutParameters = new ViewGroup.LayoutParams (WindowManagerLayoutParams.MatchParent, 100);
NextPage.Gravity = GravityFlags.CenterHorizontal;
NextPage.Text = "Next Page";
NextPage.Click += (object sender, EventArgs e) => {
UnboundService();
this.Finish();
StartActivity(typeof(SecondActivity));
};
(btnStartService.Parent as LinearLayout).AddView (NextPage);
btnStartService.Click += delegate {
BindService ();
Intent syncLoginInfoIntent = new Intent (this, typeof(BirdyService));
syncLoginInfoIntent.PutExtra ("commandType", "LoginSync");
StartService (syncLoginInfoIntent);
};
}
void BindService ()
{
Console.WriteLine ("Bind service");
base.BindService (new Intent (this, typeof(BirdyService)), _connection, Bind.AutoCreate);
_isBound = true;
}
void UnboundService ()
{
Console.WriteLine ("Unbinding service");
if (_isBound) {
((SyncServiceConnection)_connection).OnDisconnect ();
base.UnbindService (_connection);
_isBound = false;
}
}
void HandleSyncFeedback (object sender, BirdyService.SyncProgressEventArgs e)
{
this.RunOnUiThread(() =>{_serviceOutput.Text += "\n" + e.Extra;});
}
protected override void OnDestroy ()
{
base.OnDestroy ();
Console.WriteLine ("FirstActivity Destroyed!");
_connection = null;
_serviceOutput = null;
}
class SyncServiceConnection: Java.Lang.Object, IServiceConnection
{
FirstActivity _self;
public SyncServiceConnection (FirstActivity self)
{
_self = self;
}
public void OnServiceConnected (ComponentName className, IBinder service)
{
Console.WriteLine ("~~CONNECTING SERVICE!!!~~");
_self._service = ((BirdyService.SyncBinder)service).Service;
_self._service.SyncProgressEvent += _self.HandleSyncFeedback;
}
public void OnDisconnect ()
{
Console.WriteLine ("~~DISCONECTING SERVICE!!!~~");
if (_self._service != null) {
_self._service.SyncProgressEvent -= _self.HandleSyncFeedback;
_self._service = null;
}
}
public void OnServiceDisconnected (ComponentName className)
{
}
}
}
SecondActivity:
[Activity (Label = "Dvit.Apps.MemoryManager", Icon = "@drawable/icon")]
public class SecondActivity : Activity
{
int count = 1;
protected override void OnCreate (Bundle bundle)
{
base.OnCreate (bundle);
// Set our view from the "main" layout resource
SetContentView (Resource.Layout.Main);
// Get our button from the layout resource,
// and attach an event to it
}
protected override void OnDestroy ()
{
base.OnDestroy ();
Console.WriteLine ("SecondActivity Destroyed!");
}
}
服务:
[Service (Enabled = true)]
public class BirdyService:Service
{
IAzureService _azureSvc;
ISqlService _sqlSvc;
ISyncService _syncSvc;
IGlobalSettings _settings;
AndroidSqlteConnection _connection;
#region Service 'IsSyncing?' Checkers
private Boolean _syncLoginSync = false;
public Boolean IsServiceSyncing {
get {
if (_syncLoginSync == true)
return true;
else
return false;
}
}
#endregion
public class SyncProgressEventArgs:EventArgs
{
public SyncProgressEventArgs ()
{
this.Progress = 0;
this.IsCompleted = false;
}
public bool IsCompleted {
get;
set;
}
public string Extra{ get; set; }
public Int16 Progress {
get;
set;
}
}
public event EventHandler<SyncProgressEventArgs> SyncProgressEvent;
#region Binder => communication between starting activity & service
private IBinder binder;
public class SyncBinder:Binder
{
BirdyService _service;
public SyncBinder (BirdyService service)
{
_service = service;
}
public BirdyService Service {
get{ return _service; }
}
}
public override IBinder OnBind (global::Android.Content.Intent intent)
{
return binder;
}
#endregion
public BirdyService () : base ()
{
binder = new SyncBinder (this);
}
public override void OnCreate ()
{
base.OnCreate ();
var appContext = this.ApplicationContext as MemoryManagerApplication;
_settings = appContext.GlobalSettings;
_azureSvc = new AzureService (new MobileServiceClient (_settings.AzureMobileServiceUrl, _settings.AzureMobileServicePassword));
_connection = new AndroidSqlteConnection ();
_sqlSvc = new SqlService (_connection);
_syncSvc = new SyncService (_azureSvc, appContext.WebApiClient, _sqlSvc, _settings);
}
public override StartCommandResult OnStartCommand (global::Android.Content.Intent intent, StartCommandFlags flags, int startId)
{
if (intent != null) {
var command = intent.GetStringExtra ("commandType");
var keepAlive = intent.GetBooleanExtra ("keepAlive", false);
Console.WriteLine ("~~>SERVICE TASK RECEIVED COMMMANDNAME: " + command + "<~~");
switch (command) {
case "LoginSync":
{
LoginSync (intent, keepAlive);
}
break;
}
}
return StartCommandResult.Sticky;
}
#region LoginSync
private void LoginSync (global::Android.Content.Intent intent, bool keepAlive = false)
{
new Task (async () => {
try {
var progressEventArg = new SyncProgressEventArgs ();
_syncLoginSync = true;
_settings.IsSyncingOrganisations = true;
progressEventArg.Extra = "Fetching master data...";
progressEventArg.Progress = 10;
if (SyncProgressEvent != null)
this.SyncProgressEvent (null, progressEventArg);
await _syncSvc.SyncMasterData (true);
var requestUserInfoFragment = await Authenticate (progressEventArg);
_settings.IsSyncingOrganisations = false;
progressEventArg.Extra = "Completed!";
progressEventArg.Progress = 100;
progressEventArg.IsCompleted = true;
if (SyncProgressEvent != null)
SyncProgressEvent (requestUserInfoFragment, progressEventArg);
_syncLoginSync = false;
if (!IsServiceSyncing && !keepAlive)
this.StopSelf ();
} catch (Exception ex) {
_syncLoginSync = false;
//_Logger.Trace (ex.Message);
_settings.IsSyncingOrganisations = false;
if (!IsServiceSyncing)
this.StopSelf ();
throw;
}
}).Start ();
}
async Task<Boolean> Authenticate (SyncProgressEventArgs args)
{
try {
args.Extra = "Fetching user...";
args.Progress = 30;
if (this.SyncProgressEvent != null)
this.SyncProgressEvent (null, args);
Account account = await _azureSvc.AccountByGoogleId (_settings.LoginUserId);
if (account != null) {
var party = await _azureSvc.GetItemById<Party> (account.PartyId);
args.Extra = "User found, initializing user data ...";
args.Progress = 50;
if (this.SyncProgressEvent != null)
this.SyncProgressEvent (null, args);
_sqlSvc.Insert<Party> (party);
_sqlSvc.Insert<Account> (account);
args.Extra = "User found, fetching organisation data...";
args.Progress = 50;
if (this.SyncProgressEvent != null)
this.SyncProgressEvent (null, args);
//Fetch organisations
await _syncSvc.SyncPartyInitData (party.Id, true, true);
//Fetch appointments & orders
args.Extra = "Organisation data completed, fetching party data...";
args.Progress = 80;
if (this.SyncProgressEvent != null)
this.SyncProgressEvent (null, args);
await _syncSvc.SyncPartyDetailData (party.Id);
//do not request user info
return false;
} else {
//FILL IN ACCOUNT
account = new Account ();
Party party = new Party ();
party.Id = Guid.NewGuid ().ToString ();
account.Id = Guid.NewGuid ().ToString ();
account.IdentityProvider = _settings.LoginPlatform;
account.IdentityToken = _settings.LoginUserId;
account.PartyId = party.Id;
account.InfoProvider = _settings.UserInfo.RawData;
account.LoginName = _settings.LoginUserId;
//FILL IN PARTY
bool requestUserInfoFragment = false;
if (_settings.UserInfo != null) {
if (!String.IsNullOrWhiteSpace (_settings.UserInfo.FirstName)) {
party.FirstName = _settings.UserInfo.FirstName;
} else
requestUserInfoFragment = true;
if (!String.IsNullOrWhiteSpace (_settings.UserInfo.LastName)) {
party.LastName = _settings.UserInfo.LastName;
} else
requestUserInfoFragment = true;
if (!String.IsNullOrWhiteSpace (_settings.UserInfo.Email)) {
party.Email = _settings.UserInfo.Email;
} else
requestUserInfoFragment = true;
}
party.LocalIsNew = true;
account.LocalIsNew = true;
_sqlSvc.Insert<Party> (party);
_sqlSvc.Insert<Account> (account);
if (!requestUserInfoFragment) {
args.Extra = "Adding new users to the server";
args.Progress = 80;
if (this.SyncProgressEvent != null)
this.SyncProgressEvent (null, args);
await _syncSvc.SyncAllFromType<Party> ();
await _syncSvc.SyncAllFromType<Account> ();
}
//ELSE sync in newuserfragment
return requestUserInfoFragment;
}
} catch (Exception ex) {
throw;
}
}
#endregion
public override void OnDestroy ()
{
base.OnDestroy ();
Console.WriteLine ("Destroying BirdyService");
_connection.Close ();
_connection = null;
_azureSvc = null;
_sqlSvc = null;
_syncSvc = null;
_settings = null;
}
}
首先,打开严格模式以检测 activity 泄漏,首先将其添加到应用程序的 OnCreate activity:
StrictMode.SetVmPolicy (new StrictMode.VmPolicy.Builder ().DetectAll ().PenaltyLog ().Build ());
每当检测到超过 1 个 activity 类型实例时,这将向 logcat 发出警告。它看起来像这样:
[StrictMode] class md5962cfe7bc03e689322450e055e633b77.FirstActivity; instances=2; limit=1
[StrictMode] android.os.StrictMode$InstanceCountViolation: class md5962cfe7bc03e689322450e055e633b77.FirstActivity; instances=2; limit=1
[StrictMode] at android.os.StrictMode.setClassInstanceLimit(StrictMode.java:1)
接下来是为您的 activity 切断对等对象连接:
protected override void OnDestroy ()
{
base.OnDestroy ();
base.Dispose ();
GC.Collect (GC.MaxGeneration);
}
base.Dispose ()
中断了 C# 对象和 Java Vm 对象之间的对等对象连接。 http://developer.xamarin.com/guides/android/advanced_topics/garbage_collection/#Disposing_of_Peer_instances
一般来说,这应该足以修复样品的泄漏。您还可以更进一步,将 Activity 中派生自 Java.Lang.Object 的所有对象置为空。例如:
protected override void OnDestroy ()
{
button.Dispose ();
button = null;
base.OnDestroy ();
base.Dispose ();
GC.Collect (GC.MaxGeneration);
}
你的问题的核心是你不知道哪些内容仍在被引用,以及哪些内容正在引用它。
使用 Android Studio 中的工具追踪内存分配位置应该很简单。 Memory Profiling 101 介绍如何使用内存监视器、分配跟踪器和堆查看器来查找具体问题。
真的,这些工具可以让您非常清楚地了解内存的去向。我将从那里开始,窥探你的第二个 activity 仍然掌握的内容。