פורסם 2010 באפריל 515 שנים שלום אנשים.אני קצת עושה התנסויות בסוקטים. כתבתי תכנית ששולחת קבצים לסרבר.אני מבצע בדיקות ב TASK MANAGER כדי לראות בערך כמה זכרון התכנית צורכת.המצב הוא כזה:כשאני מריץ את התכנית (WINDOWS FORM), היא תופסת בזכרון כ 3.7MBלאחר שאני מוסיף 80 קבצים לרשימת LISTVIEW, הזכרון עולה לכ 4.3MBעד כאן זה בסדר גמור.ברגע שאני לוחץ על כפתור השליחה, הקבצים שלחים בסדר, רואים קפיצות בזכרון בן 10 ל 30 מגה.הקבצים שאני שולח, כל אחד הוא בערך מגה, ואני לא שולח אותם במכה, אלה אחד אחד.לאחר שכל הקבצים נשלחו, כשאני מסתכל על כמות הזכרון, היא על 47MB!ניסיתי לעשות DISPOSE לאובייקטים שאפשר, ולתת לאובייקטים בסיום השימוש NULL (כדי שאוסף הזבל יעלה עליהם?..)איך אני פותר בעיות זכרון?יש לציין, שאם אחרי זה אני שולח שוב את אותם 80 קבצים, כשהזכרון הוא כבר על 47MB, הוא נשאר בערך אותו דבר לאחר השליחה השניה של כל הקבצים. כלומר, הזכרון לא מתנפח בכל פעם שאני מבצע שליחה, הוא מתייצב על 47 לאחר כל שליחה. אבל אני מצפה שלאחר השליחה, הוא יחזור ל 3-4 מגה כמו שהוא היה בתחילת הריצה של התכנית.רעיונות מישהו?
פורסם 2010 באפריל 515 שנים אתה נכנס פה לנושא דיי מסובך (תחקור תקלות בזמן ריצה).יש הון דרכים לקוף תקלות מסוג זה, ולהסביר אותן פה בפורם זה דיי מסובך עד בלתי אפשרי.אני מציע לך לחפש כלי profiler חינמי שאיתו תסתכל על מצב האובייקטים שלך בזכרון, ותראה איזה סוג אובייקט תופס יותר זכרון (כמות אובייקטים*גודל אובייקט בזכרון), ואז נסה להבין בקוד שלך איפה אתה עדיין מחזיק reference אליו (יכול להיות שיש לך איזה list שהאוייקבטים עדיין נשארים בו ולא משתחררים?).אני מציע לך לעשות עוד דבר.נסה לשלוח כמה קבצים, ולאחר שהם נשלחים (ומתנקים מהזכרון, לפי מה שאני מבין), נסה לשלוח עוד, ואז תראה מה קורה לזכרון (נטר את זה בצורה זו כמה פעמים).כי יכול להיות שלא מדובר בזליגת זכרון, אלא שככה באמת התוכנה אמורה לעבוד (הרי נטענים לך לזכרון עוד אובייקטים של הframework עצמו, שלא בטוח שצריכים להיזרק ע"י תהליך הGC).
פורסם 2010 באפריל 515 שנים מחבר תודה רבה על התגובה.המצב הוא ממש מוזר.ניסתי לראות מה קורה עם שליחה של קובץ אחד.הזכרון קובץ ל11 מגה.שליחה של אותו קובץ, מיד לאחר מכן, מקפיצה לפעמים את הזכרון ל 19, וכשאני שולח שוב, הזכרון יורד ל 9, ועולה, ויורד, כמו מצבי רוח של אישה.הבעיה העיקרית פה, היא שאני לא ממש מוצא עקביות.אותה פעולה שאני עושה שמקפיצה את הזכרון, לפעמים מקפיצה יותר/פחות, ולפעמים מורידה מהצריכת זכרון.אוקיי, הצלחתי לצמצם את הבעיה, אני יודע איזו פוקציה גורמת לזה, זו הפונקציה ששולחת את הקבצים.אני אחטט שם שוב יותר ביסודיות לראות מה לא משתחרר שם.יש טיפים לגבי ניקוי זכרון ב C# חוץ מלעשות DISPOSE למה שאפשר או להציב NULL באובייקטים?הנה הפונקציה ששולחת קובץ:public int SendFile(string FilePath) { if (!this.IsConnected()) //Connect if neccesary if (this.Connect() == false) return -1; //server offline StreamWriter writeFileData; NetworkStream nStream; string Base64ImageData; string BlockData; int RemainingStringLength = 0; bool Done = false; nStream = client.GetStream(); writeFileData = new StreamWriter(nStream); int i; for (i = FilePath.Length - 1; i >= 0 && FilePath[i] != '\\' && FilePath[i] != '/'; i--) ;//set i to begining of filename i++; string filename=FilePath.Substring(i,FilePath.Length-i);//get filename without path FileStream fs = File.OpenRead(FilePath); //Open file byte[] ImageData = new byte[fs.Length]; fs.Read(ImageData, 0, ImageData.Length); //Read file bytes to fs Base64ImageData = Convert.ToBase64String(ImageData); int startIndex = 0; try { byte[] filename_len = new byte[sizeof(int)]; writeFileData.Write('F'); writeFileData.Flush(); filename_len = BitConverter.GetBytes((int)filename.Length); nStream.Write(filename_len,0,sizeof(int)); writeFileData.Write(filename); writeFileData.Flush(); while (Done == false) { while (startIndex < Base64ImageData.Length) { try { BlockData = Base64ImageData.Substring(startIndex, 1000); writeFileData.WriteLine(BlockData); writeFileData.Flush(); startIndex += 1000; } catch { RemainingStringLength = Base64ImageData.Length - startIndex; BlockData = Base64ImageData.Substring(startIndex, RemainingStringLength); writeFileData.WriteLine(BlockData); writeFileData.Flush(); Done = true; break; } } } writeFileData.Close(); //CLEAN writeFileData.Dispose(); nStream.Dispose(); Base64ImageData = null; BlockData = null; nStream.Dispose(); writeFileData.Dispose(); fs.Dispose(); Array.Resize(ref ImageData, 0); ImageData = null; } catch (Exception er) { MessageBox.Show("Unable to connect to server\r\n"+er.Message); } //if all went OK return Bytes sent: //return Base64ImageData.Length; return 1; }עדכוןאוקיי אחרי דבאג צעד צעד, אני חושב שמה שמקפיץ את הזכרון זו השורה הבאה:Base64ImageData = Convert.ToBase64String(ImageData);אחרי שהשורה הזאת מתבצעת הזכרון קופץ ב 3 מגה בערך.איך אני יכול לסדר את זה?חשבתי אולי ליצור הפניה ל CONVERT ואז לשחרר אותה איכשהו, אבל הקומפיילר אומר שזו מחלקה סטטית ואני לא יכול ליצור ממנה אובייקט.הבעיה היא לא ב Base64ImageData שאליו אני עושה את ההשמה.הזכרון קופץ גם אם אני ארשום רק את השורה :Convert.ToBase64String(ImageData);
פורסם 2010 באפריל 815 שנים אני לא רוצה להפריע.. אבל כאשר אתה עושה את הפעולה הזו:Base64ImageData = Convert.ToBase64String(ImageData);נראה לי שאתה מכניס את כל התמונה לתוך משתנה (והמשתנה כמובן נמצא בזיכרון).האם אני טועה?
פורסם 2010 באפריל 815 שנים טיפ קטן (אני לא חושב שזה מה שגורם לבעיה, אבל בכל זאת): עדיף להשתמש ב-using מאשר להשתמש ב-Dispose. משתמשים ב-Dispose רק כאשר אתה מקצה ומשחרר את האובייקט בשתי פונקציות שונות (ואז אתה לא יכול להשתמש ב-using).
פורסם 2010 באפריל 815 שנים מחבר אני לא רוצה להפריע.. אבל כאשר אתה עושה את הפעולה הזו:Base64ImageData = Convert.ToBase64String(ImageData);נראה לי שאתה מכניס את כל התמונה לתוך משתנה (והמשתנה כמובן נמצא בזיכרון).האם אני טועה?נכון, אבל זה משתנה לוקאלי, הוא אמור להימחק אחרי שהפונקציה מסתיימת.מה שלא מתפנה מהזכרון, זה הפעולה ש CONVERT עושה, בלי שום קשר להשמה שעשיתי.טיפ קטן (אני לא חושב שזה מה שגורם לבעיה' date=' אבל בכל זאת): עדיף להשתמש ב-using מאשר להשתמש ב-Dispose. משתמשים ב-Dispose רק כאשר אתה מקצה ומשחרר את האובייקט בשתי פונקציות שונות (ואז אתה לא יכול להשתמש ב-using).[/quote']מה זאת אומרת להשתמש ב USING? לא הבנתי ממש מה הם קשורים. USING זה כמו INCLUDE עד כמה שאני יודע, לא? ולמה בדיוק אני יעשה USING?אפשר דוגמא?--- לא משנה הבנתי מה זה. תודה. (אגב, לא פותר את הבעיה).
פורסם 2010 באפריל 815 שנים קרה לי כבר בעבר שה-Garbage Collection בתוכנה גרפית מסויימת לא עבד כמו שצריך, ואחרי כמה ימים של עבודה רצופה כל הזכרון של המחשב נבלע והוא קרס.תפעיל את ה-Garbage Collection ידנית.http://www.developer.com/net/csharp/article.php/3343191/C-Tip-Forcing-Garbage-Collection-in-NET.htm
פורסם 2010 באפריל 815 שנים מחבר וואי תודה, מגניב. חשבתי שלא ניתן להפעיל אתו ידנית.בכל מקרה, עכשיו הצלחתי סידרתי את הבעיה, שיניתי קצת את המימוש של שליחת הקובץ.במקום לקרוא את כל הקובץ, אני קורא חתיכות של 1000 בתים ושולח כל פעם.עכשיו בסיום שליחת 80 קבצים, התכנית תופסת בערך 4 מגה זכרון, במקום 47 מה שהיה לפני זה.תודה לכולם.
פורסם 2010 באפריל 815 שנים זה מה שניסיתי לומר לך קודם.לקחת את כל התמונה ולשלוח אותה במכה אחת.. זה ממש לא דרך תכנותי וממש לא יעיל.הדרך הכי יעילה זה לשלוח את התמונה בחלקים קטנים.הייתי ממליץ לך ליצור CONST ב-INT שיסמן כמה בתים לשלוח כל פעם.ככה יהיה לך יותר יעילות בקוד ונוחות לשדרוג.
פורסם 2010 באפריל 815 שנים גם ליידע את הGC מתי לרוץ בקוד זה לא כזה "תכנות חכם".כל הקטע של שימוש בפריימוורק הוא למנוע מהמתכנת את המשחק עם הזכרון.אני חושב שהבנתי את ה"בעיה" שיש לך.אתה קורא קובץ גדול לתוך אובייקט (זה קורה כאשר אתה עושה את הbase64 של התמונה - שאגב מגדיל את האובייקט ב20% בערך מגודל התמונה). לכן הפריימוורק שומר את האובייקט בlarge object heap (איזור בזכרון אשר מוגדר לאובייקטים שהם מעל 20000 בייטים), שההבדל בינו לבין שאר הheapים שיש לפרוסס dotnetי (generation0,1,2) הוא שלאחר שהGC ניקה את האובייקט מהזכרון, הוא לא מקטין את הheap.הסיבה שהheap של הlarge object לא מוקטן ע"י הGC היא שמדובר בהקטנה משמעותית של השטח בזכרון, והמון משחק עם הקצאות, וכל זה תופס בעצם המון זמן מעבד.לכן מה שקורה בפעול הוא שהGC רץ, מפנה את המקום בheap הרלוונטי, אבל לא משנה את גודל הפרוסס בזכרון. לאחר מכן, כאשר אתה קורא עוד ועוד תמונות, אזי הפרוסס משתמש באותו זכרון שהוא כבר תפס עבור הlarge objects.אני מניח שמה שקורה כאשר אתה מפעיל בעצמך את הgc הוא שמתבצע גם הקיצוץ בזכרון, ואז הכל מתפנה לך.זה דיי על רגל אחת, אני מציע לך לקרוא קצת על המנגנון הזה.כדאי להתחיל עם זה במאמר הזה:http://msdn.microsoft.com/en-us/magazine/bb985010.aspxhttp://msdn.microsoft.com/en-us/magazine/bb985011.aspx (בעמוד השני מציגים שיטה לבחון את מצב הheapים של הפרוסס שלך)על כל פנים, אם היית פועל לפי ההודעה הקודמת שלי, היית מגלה את זה בעזרת הפרופיילר.
פורסם 2010 באפריל 815 שנים מחבר תודה על התגובה המפורטת.זה באמת מייצג את הבעיה שהייתה לי.אני רק התחלתי ללמוד C# הסמסטר הזה, ואני סתם מחפש לי אתגרים (חוץ ממה שלימדו אותי בקורס, כמו משחק איקס עיגול מטופש), ואני לא הכי בקיא ב NET.בכל מקרה, הקטע קוד שהשתמשתי נלקח מהאינטרנט, ועבר שיפוצים שלי.החלטתי שפשוט עדיף לא לקרוא את כל הקובץ לזכרון, כי בגדול רציתי שזה יהיה די אוניברסלי, ויהיה אפשר לשלוח קבצים ללא הגבלה של הגודל.לגבי ה PROFILER, חיפשתי לא מעט עד שמצאתי אחד חינמי, והורדתי אותו, אבל לפני שיצא לי לנסות אותו (וגם אין לי מושג איך עובדים עם PROFILER) כבר סידרתי את הקטע קוד העקום הזה שמצאתי.משום מה עכשיו אני לא מוצא את ההורדה ואני לא זוכר איך הוא נקרא, אתה יכול להמליץ על משהו טוב חינמי? אני די אשמח לחקור את עניין ה PROFILER.תודה.
ארכיון
דיון זה הועבר לארכיון ולא ניתן להוסיף בו תגובות חדשות.