2011-02-15 2 views
3

저는 Instruments와 함께 매우 기본적인 테스트 앱을 실행 중이며 많은 메모리 누수가 발생합니다! App이 iTunes에 제출 될 때 Apple 직원이 유출 된 메모리를 검사한다는 것을 알고 있기 때문에 문제를 조사하고 싶습니다.MonoTouch는 왜 아주 간단한 Apps에서도 (Instruments에서보고 한 것처럼) 많은 메모리 누출을 유발합니까?

내 환경 : Mac OS X 10.6.6의 MonoDevelop 3.2.4, iOS 4.2.1을 실행하는 iPad를 타겟팅하는 MonoDevelop 2.4.2.

내 테스트 앱에는 시작 문자로 그룹화 한 50 개의 문자열 목록이 채워진 TableView가 표시됩니다.

문제를 재현하는 방법 : MonoDevelop를 사용하여 새 "iPad Window 기반 프로젝트"를 만들고 Interface Builder로 MainWindow.xib 파일을 열고 새 TableView를 창에 배치하고 해당 콘센트 ("tview")를 만듭니다. AppDelegate 클래스에 추가합니다. 그런 다음 Main.cs에 다음 코드를 입력 :

나는 장치에 다음 테스트를 수행 한
using System; 
    using System.Collections.Generic; 
    using System.Linq; 
    using MonoTouch.Foundation; 
    using MonoTouch.UIKit; 

    namespace SimpleTable 
    { 
     public class Application 
     { 
      static void Main (string[] args) 
      { 
       UIApplication.Main (args); 
      } 
     } 

     public partial class AppDelegate : UIApplicationDelegate 
     { 
      private List<string> _names; 

      public override bool FinishedLaunching (UIApplication app, NSDictionary options) 
      { 
       _names = new List<string> { "Smith", "Jones", "Williams", "Brown", "Taylor", 
              "Davies", "Wilson", "Evans", "Thomas", "Johnson", 
              "Roberts", "Walker", "Wright", "Robinson", "Thompson", 
              "White", "Hughes", "Edwards", "Green", "Hall", 
              "Wood", "Harris", "Lewis", "Martin", "Jackson", 
              "Clarke", "Clark", "Turner", "Hill", "Scott", 
              "Cooper", "Morris", "Ward", "Moore", "King", 
              "Watson", "Baker", "Harrison", "Morgan", "Patel", 
              "Young", "Allen", "Mitchell", "James", "Anderson", 
              "Phillips", "Lee", "Bell", "Parker", "Davis" }; 
       tview.Source = new MyTableViewSource(_names); 

       window.MakeKeyAndVisible(); 

       return true; 
      } 

      private class MyTableViewSource : UITableViewSource 
      { 
       private List<string> _sectionTitles; 
       private SortedDictionary<int, List<string>> _sectionElements = new SortedDictionary<int, List<string>>(); 

       public MyTableViewSource(List<string> list) 
       { 
        // Use LINQ to find the distinct set of alphabet characters required. 
        _sectionTitles = (from c in list select c.Substring(0, 1)).Distinct().ToList(); 

        // Sort the list alphabetically. 
        _sectionTitles.Sort(); 

        // Add each element to the List<string> according to the letter it starts with 
        // in the SortedDictionary<int, List<string>>. 
        foreach (string element in list) 
        { 
         int sectionNum = _sectionTitles.IndexOf(element.Substring(0, 1)); 
         if (_sectionElements.ContainsKey(sectionNum)) 
         { 
          // SortedDictionary already contains a List<string> for that letter. 
          _sectionElements[sectionNum].Add(element); 
         } 
         else 
         { 
          // First time that letter has appeared, create new List<string> in the SortedDictionary. 
          _sectionElements.Add(sectionNum, new List<string> { element }); 
         } 
        } 
       } 

       public override int NumberOfSections(UITableView tableView) 
       { 
        return _sectionTitles.Count; 
       } 

       public override string TitleForHeader(UITableView tableView, int section) 
       { 
        return _sectionTitles[section]; 
       } 

       public override int RowsInSection(UITableView tableview, int section) 
       { 
        return _sectionElements[section].Count; 
       } 

       public override UITableViewCell GetCell(UITableView tableView, NSIndexPath indexPath) 
       { 
        string kCellIdentifier = "mycell"; 
        UITableViewCell cell = tableView.DequeueReusableCell(kCellIdentifier); 
        if (cell == null) 
        { 
         // No re-usable cell found, create a new one. 
         cell = new UITableViewCell(UITableViewCellStyle.Default, kCellIdentifier); 
        } 

        string display = _sectionElements[indexPath.Section][indexPath.Row]; 
        cell.TextLabel.Text = display; 

        return cell; 
       } 

       public override void RowSelected(UITableView tableView, NSIndexPath indexPath) 
       { 
        string display = _sectionElements[indexPath.Section][indexPath.Row]; 

        showAlert("RowSelected", "You selected: \"" + display + "\""); 

        // Prevent the blue 'selection indicator' remaining. 
        tableView.DeselectRow(indexPath, true); 
       } 

       private void showAlert(string title, string message) 
       { 
        using (var alert = new UIAlertView(title, message, null, "OK", null)) 
        { 
         alert.Show(); 
        } 
       } 
      } 
     } 
    } 

:

  1. public override string TitleForHeader(UITableView tableView, int section) 
    

    절차 주석이, 내에서 앱을 출시 도구 : 단일 누설이 발견되었습니다. 빈 앱을 테스트 할 때조차도 항상 누출 된 것 같습니다! 누출이 많이 발견되고, 위, 아래의 표를 스크롤 및/또는 선택할 때 자신의 번호는 최대 성장 :

    Test 1 Instruments screenshot

  2. 주석

    public override string TitleForHeader(UITableView tableView, int section) 
    

    절차는 악기 내에서 앱을 출시 열.

    Test 2 Instruments screenshot

  3. 치환

    return "Test Header…"; 
    

    (따라서 일정한 strin를 사용하여 함께

    public override string TitleForHeader(UITableView tableView, int section) 
    

    절차의

    return _sectionTitles[section]; 
    

    문 g) : 테스트 n.2와 동일!

MonoTouch는 도청 되었습니까? 아니면 필수적인 것을 잊어 버렸습니까? 이러한 단순한 애플리케이션조차도 몇 분 동안 실행될 때 수백 가지 메모리 누수가 발생한다면 실제 (더 복잡한) 애플리케이션으로 어떤 일이 발생할 수 있습니까?

웹을 광범위하게 검색했지만이 문제에 대한 중요한 게시물을 찾지 못했습니다 ... 모든 기여가 크게 감사하겠습니다.

+0

마찬가지로 FYI; 귀하의 스크린 샷이 작동하지 않습니다 – Luke

+0

죄송합니다 ... 해결되었습니다! –

답변

3

monotouch와 모노 VM이 메모리를 할당하고 관리하는 방법은 악기로 완전히 이해되지 않습니다. 애플은 이것에 대한 어떤 신청도 거절하지 않았다.누수라고 생각되는 특정 버그가 있다면

에 문제를 제기하십시오. 나는 당신의 스크린 샷을보고 16 바이트 누수가 발생할 수 있다는 것을 알았습니다. 다가오는 모노 터치 4에 맞춰 수정했습니다.

+0

답변을 주셔서 감사합니다, Geoff,하지만 ... "모노 VM"이란 정확히 무엇을 의미합니까? 내가 아는 한 MonoTouch 앱은 Ahead Of Time (SDK에 대한 Apple의 라이센스 및 iPhone/iPad로 개발 한 응용 프로그램에서 코드를 해석하거나 동적으로 컴파일 할 수 없음) 시간대로 컴파일됩니다. MonoDevelop/MonoTouch에 의해 컴파일 된 코드는 XCode/Objective-C로 컴파일 된 코드와 구별 할 수 없다고 생각했습니다. 두 방법 모두 ARM 원시 코드를 생성해야합니다 ... (계속) –

+0

또한 C# 코드는)가 iOS 네이티브 API의 호출에 맵핑되고 컴파일 프로세스가 iOS 고유 메모리 관리 모델 (참조 계산 등)과 호환된다는 것을 나타냅니다. 답장에서 C# 소스에서 컴파일 된 바이너리 코드는 Objective-C 소스에서 컴파일 된 바이너리와 다른 방식으로 메모리를 관리합니다. 사실입니까? 나는 꽤 혼란 스럽다 ...이 주제에 대한 철저한 설명은 어디에서 찾을 수 있습니까? 미리 감사드립니다 ... –

+0

몇 가지 질문을 작은 댓글 섹션에 담았습니다. Mono Virtual Machine은 모든 응용 프로그램에 여전히 존재하지만 AOT'd 어셈블리 코드와 함께 작동하는 C 코드 일뿐입니다. 관리 객체에는 적절한 가비지 수집에 필요한 자체 객체 힙이 있습니다. 그게 높은 수준의 설명, 자세한 내용은 http://monotouch.net/보세요. –

관련 문제