Bellek yönetimi ile ilgili giriş seviyesi mühendis sorusu


9

Giriş seviyesi bir yazılım geliştirici olarak pozisyonuma başladığımdan bu yana birkaç ay geçti. Şimdi bazı öğrenme eğrileri geçmişim (örneğin dil, jargon, VB ve C # sözdizimi) daha iyi yazılım yazmak için daha ezoterik konulara odaklanmaya başlıyorum.

Bir iş arkadaşına sunduğum basit bir soruya "Yanlış şeylere odaklanıyorum" şeklinde yanıt verildi. Bu iş arkadaşına saygı duysam da bunun üzerinde durulması gereken "yanlış bir şey" olduğuna katılmıyorum.

İşte kod (VB'de) ve ardından soruydu.

Not: GenerateAlert () İşlevi bir tamsayı döndürür.

Dim alertID as Integer = GenerateAlert()
_errorDictionary.Add(argErrorID, NewErrorInfo(Now(), alertID))    

vs...

 _errorDictionary.Add(argErrorID, New ErrorInfo(Now(), GenerateAlert()))

Aslında ikincisini yazdım ve "Dim alertID" ile yeniden yazdım, böylece başkası okumayı daha kolay bulabilirdi. Ama işte endişem ve sorum buydu:

Dim DimtID ile bu yazı yazılırsa, aslında daha fazla bellek kaplar; sonlu fakat daha fazladır ve bu yöntem birçok kez çağrılmalı mı, bir soruna yol açabilir mi? .NET bu nesne AlertID nasıl işleyecek. .NET dışından biri kullanımdan sonra nesneyi el ile atmalıdır (alt bölümün sonuna yakın).

Sadece çöp toplamaya dayanmayan bilgili bir programcı olmamı sağlamak istiyorum. Bunu düşünüyor muyum? Yanlış şeylere mi odaklanıyorum?


1
İlk versiyonun daha okunabilir olması nedeniyle% 100 olduğunu kolayca anlatabilirim. Derleyicinin neyle ilgilendiğinizi bile halledebileceğinden emin olabilirim. Olmasa bile, zamanından önce optimizasyon yapıyorsunuz.
Rig

6
Gerçekten adlandırılmış bir tamsayı vs anonim bir tamsayı ile daha fazla bellek kullanacağından emin değilim. Her durumda, bu gerçekten erken optimizasyon. Bu düzeyde verimlilik konusunda endişelenmeniz gerekiyorsa (neredeyse emin değilsiniz) C # yerine C ++ 'a ihtiyacınız olabilir. Performans sorunlarını ve kaputun altında neler olduğunu anlamak iyidir, ancak bu büyük bir ormanda küçük bir ağaçtır.
psr

5
Adlı vs anonim tamsayı, özellikle anonim bir tamsayı yalnızca SİZİN adsız bir adlandırılmış tamsayı olduğundan (derleyici yine de adlandırmak zorundadır) daha fazla bellek kullanmaz. En çok, adlandırılan tamsayı farklı bir kapsama sahip olur, böylece daha uzun yaşayabilir. Anonim tamsayı yalnızca yönteme ihtiyaç duyulduğu sürece, adlandırılmış olan tam sayı üst öğesinin gerektirdiği sürece yaşayacaktır.
Joel Etherton

Bakalım ... Tamsayı bir sınıfsa, öbek üzerinde tahsis edilecektir. Yerel değişken (büyük olasılıkla yığın üzerinde) ona bir başvuru tutar. Başvuru, errorDictionary nesnesine iletilecektir. Çalışma zamanı başvuru sayımı (veya benzeri) yapıyorsa, daha fazla başvuru olmadığında, o (nesne) öbekten çıkarılır. Yöntem çıktıktan sonra istif üzerindeki her şey otomatik olarak "serbest bırakılır". İlkel bir şeyse, büyük olasılıkla yığınla sonuçlanacaktır.
Paul

İş arkadaşınız haklıydı: sorunuzun ortaya koyduğu sorun optimizasyon değil, okunabilirlikle ilgili olmalıdır .
haylem

Yanıtlar:


25

"Erken optimizasyon, programlamadaki tüm kötülüklerin (veya en azından çoğunun) köküdür." - Donald Knuth

İlk geçişiniz söz konusu olduğunda, doğru ve temiz olması için kodunuzu yazmanız yeterlidir. Daha sonra kodunuzun performans açısından kritik olduğu belirlenirse (buna profilers adı verilen araçları belirlemek için araçlar varsa), yeniden yazılabilir. Kodunuzun performans açısından kritik olduğu belirlenmezse, okunabilirlik çok daha önemlidir.

Bu performans ve optimizasyon konularını araştırmaya değer mi? Kesinlikle, ama gereksiz olursa şirketinizin doları üzerinden değil.


1
Başka kimin doları üzerinde olmalı? İşvereniniz becerilerinizdeki artıştan sizden çok faydalanıyor.
Marcin

Mevcut görevinize doğrudan katkıda bulunmayan konular? Bunları kendi zamanınızda takip etmelisiniz. Oturup merakımı gün boyunca artıran her CompSci öğesini araştırsaydım, hiçbir şey yapmazdım. Akşamlarım bunun için.
Christopher Berman

2
Tuhaf. Bazılarımızın kişisel bir hayatı var ve dediğim gibi işveren öncelikle araştırmalardan faydalanıyor. Anahtar, bütün günü bunun üzerinde harcamamaktır.
Marcin

6
Aferin. Yine de gerçekten evrensel bir kural oluşturmuyor. Ayrıca, işçilerinizi işyerinde öğrenmekten caydırırsanız, yaptığınız tek şey onları öğrenmekten caydırmak ve onları gerçekten personel gelişimi için ödeme yapan başka bir işveren bulmaya teşvik etmektir.
Marcin

2
Yukarıdaki yorumlarda belirtilen görüşleri anlıyorum; Öğle tatilim sırasında sorduğumu belirtmek isterim. :). Buraya ve Yığın Değişimi sitesi girişiniz için tekrar teşekkür ederiz; paha biçilmez!
Sean Hobbs

5

Ortalama .NET programınız için, evet, bu çok düşünüyor. .NET içinde olup bitenlerin somun ve cıvatalarına inmek isteyeceğiniz zamanlar olabilir, ancak bu nispeten nadirdir.

Sahip olduğum zor geçişlerden biri, 90'lı yıllarda C ve MASM kullanmaktan klasik VB'de programlamaya geçmekti. Her şeyi boyut ve hız için optimize etmeye alışkındım. Bu düşünceyi çoğunlukla bırakmak ve VB'nin etkili olabilmesi için bir şey yapmasına izin vermek zorunda kaldım.


5

İş arkadaşım her zaman söylediği gibi:

  1. Çalışmasını sağla
  2. Tüm hataları düzeltin, kusursuz çalışmasını sağlayın
  3. KATI yap
  4. Yavaş çalışıyorsa optimizasyonu uygulayın

Başka bir deyişle, KISS'i daima aklınızda bulundurun (basit salak tutun). Çünkü aşırı mühendislik, bazı kod mantığını aşırı düşünmek, bir dahaki sefere mantığı değiştirmek için bir sorun olabilir. Ancak, kodu temiz ve basit tutmak her zaman iyi bir uygulamadır .

Ancak, zaman ve deneyime göre, hangi kodun koktuğunu ve yakında optimizasyona ihtiyaç duyacağınızı daha iyi bilirsiniz.


3

Dim DimtID ile bunu yazmalı mı

Okunabilirlik önemlidir. Sizin örnekte olsa da, ben gerçekten şeyler yapıyoruz emin değilim o daha okunabilir. GenerateAlert () iyi bir isme sahip ve çok fazla gürültü eklemiyor. Muhtemelen zamanınızın daha iyi kullanımları vardır.

aslında daha fazla bellek kaplardı;

Sanmıyorum. Bu derleyici için nispeten basit bir optimizasyon.

Bu yöntemin birçok kez çağrılması bir soruna yol açabilir mi?

Yerel bir değişkenin aracı olarak kullanılması, çöp toplayıcı üzerinde herhangi bir etki yaratmaz. GenerateAlert () new bellekte ise, önemli olacaktır. Ancak bu, yerel değişkenden bağımsız olarak önemli olacaktır.

.NET bu nesne AlertID nasıl işleyecek.

AlertID bir nesne değil. GenerateAlert () sonucu nesnedir. AlertID, yerel bir değişkense, şeyleri takip etme yöntemiyle ilişkili alan olan değişkendir.

.NET dışından biri kullanımdan sonra nesneyi el ile atmalıdır

Bu, ilgili bağlama ve GenerateAlert () tarafından sağlanan örneğin sahiplik semantiğine bağlı olan daha yoğun bir sorudur. Genel olarak, oluşturulan örnek ne olursa olsun onu silmelidir. Programınız, manuel bellek yönetimi göz önünde bulundurularak tasarlandıysa büyük olasılıkla önemli görünecektir.

Sadece çöp toplama sürecini yürütmeyen bilgili bir programcı olmamı sağlamak istiyorum. Bunu düşünüyor muyum? Yanlış şeylere mi odaklanıyorum?

İyi bir programcı, çöp toplayıcı da dahil olmak üzere mevcut araçları kullanır. Şeyleri düşünmekten habersiz yaşamaktan daha iyidir. Yanlış şeylere odaklanıyor olabilirsiniz, ancak burada olduğumuz için bunu da öğrenebilirsiniz.


2

Çalışmasını sağlayın, temizleyin, KATI yapın, SONRA çalışması gereken kadar hızlı çalışmasını sağlayın .

Bu normal şeylerin sırası olmalı. İlk önceliğiniz, gereksinimleri ortadan kaldıran kabul testlerini geçecek bir şey yapmaktır. Bu sizin birinci önceliğinizdir çünkü müşterinizin birinci önceliği; geliştirme süreleri içinde fonksiyonel gereksinimlerin karşılanması. Bir sonraki öncelik, anlaşılması kolay temiz ve okunabilir kod yazmaktır ve böylece gerektiğinde herhangi bir WTF olmadan gelecek durumunuz tarafından korunabilir (neredeyse hiç "" sorusu "sorusu yoktur; siz veya gittikten sonra birileri geri girin ve bir şeyi değiştirin / düzeltin). Üçüncü öncelik, kodu, yine bakıma yardımcı olan modüler, yeniden kullanılabilir, değiştirilebilir parçalara yerleştiren SOLID yöntemine (veya isterseniz GRASP) uymasını sağlamaktır (sadece ne yaptığınızı ve nedenini anlayamazlar, ancak cerrahi kodları cerrahi olarak çıkarabildiğim ve değiştirebileceğim temiz çizgiler var). Son öncelik performanstır; kod, performans özelliklerine uymak için yeterince önemliyse, önce doğru, temiz ve SOLID yapılması neredeyse kesinlikle önemlidir.

Christopher (ve Donald Knuth) yankılanıyor, "erken optimizasyon tüm kötülüğün köküdür". Buna ek olarak, düşündüğünüz optimizasyon türleri hem küçük (kaynak kodunda bir ad verip vermeseniz de yığında yeni nesnenize bir başvuru oluşturulacaktır) hem de derlenmiş bir fark yaratmayabilecek bir türdür IL. Değişken isimleri IL'ye taşınmaz, bu nedenle değişkeni ilk (ve muhtemelen sadece) kullanımından hemen önce bildirdiğiniz için, IL'nin iki örneğiniz arasında özdeş olduğu bir bira parası bahse girerim. Yani, iş arkadaşınız% 100 doğru; optimize edilmiş bir şey için adlandırılmış değişken vs satır içi örneklemeye bakıyorsanız yanlış yere bakıyorsunuz.

.NET'teki mikro optimizasyonlar neredeyse hiç buna değmez (Vakaların yaklaşık% 99.99'undan bahsediyorum). C / C ++ 'da, belki, ne yaptığınızı biliyorsanız. Bir .NET ortamında çalışırken, kodun yürütülmesinde önemli bir ek yükün bulunduğu donanımın metalinden yeterince uzaktasınız. Bu nedenle, halihazırda kabarma hızından vazgeçtiğinizi ve bunun yerine "doğru" kod yazmak istediğinizi belirten bir ortamda olduğunuz göz önüne alındığında, bir .NET ortamında bir şey gerçekten yeterince hızlı çalışmıyorsa, karmaşıklığı çok yüksek, ya da paralelleştirmeyi düşünmelisiniz. İşte optimizasyon için izlenmesi gereken bazı temel işaretler; Optimizasyondaki verimliliğinizi (harcanan zaman için kazanılan hız) hızlandıracağınızı garanti ediyorum:

  • İşlev şeklini değiştirmek, katsayıları değiştirmekten daha önemlidir - WRT Big-Oh karmaşıklığı, bir N 2 algoritmasında uygulanması gereken adım sayısını yarıya düşürebilirsiniz ve yine de yürütüldüğünde bile ikinci dereceden karmaşıklık algoritmasına sahip olursunuz. eskiden yarısı. Bu tür bir sorun için karmaşıklığın alt sınırı buysa, öyle olsun, ancak aynı soruna NlogN, doğrusal veya logaritmik bir çözüm varsa, karmaşıklığı azaltmak için algoritmaları değiştirerek, sahip olduğunuz sorunu optimize etmekten daha fazla kazanacaksınız.
  • Karmaşıklığı görememeniz bunun size mal olmadığı anlamına gelmez - Kelimedeki en zarif tek astarların çoğu korkunç performans gösterir (örneğin, Regex prime checker üstel bir karmaşıklık işlevidir, ancak verimli sayının karekökünden daha küçük tüm asal sayılara bölünmesini içeren asal değerlendirme O (Nlog (sqrt (N))) düzenindedir Linq, kodu basitleştirdiği için harika bir kütüphanedir, ancak bir SQL motorunun aksine .Net derleyici, sorgunuzu yürütmenin en etkili yolunu bulmaya çalışmaz.Bir yöntem kullandığınızda ne olacağını ve dolayısıyla bir zincirin daha önce (veya daha sonra) yerleştirilirken neden daha hızlı olabileceğini bilmelisiniz. aynı sonuçlar.
  • OTOH, neredeyse her zaman kaynak karmaşıklığı ile çalışma zamanı karmaşıklığı arasında bir dengeye sahiptir - SelectionSort'un uygulanması çok kolaydır; muhtemelen 10LOC veya daha az bir sürede yapabilirsiniz. MergeSort biraz daha karmaşık, Quicksort daha fazla ve RadixSort daha da fazla. Ancak, algoritmalar kodlama karmaşıklığında (ve dolayısıyla "önden" geliştirme süresinde) arttıkça, çalışma zamanı karmaşıklığında azalırlar; MergeSort ve QuickSort NlogN'dir ve RadixSort genellikle doğrusal olarak kabul edilir (teknik olarak NlogM'dir, burada M, N'deki en büyük sayıdır).
  • Hızlı kırın - Ucuz olması muhtemel, doğru olması muhtemel olan ve devam edebileceğiniz anlamına gelen bir kontrol varsa, önce bu kontrolü yapın. Örneğin, algoritmanız yalnızca 1, 2 veya 3 ile biten sayıları önemsiyorsa, en olası durum (tamamen rastgele veriler verilir) başka bir basamakla biten bir sayıdır, bu nedenle sayının bitmediğini test edin 1, 2 veya 3'e bakın, sayının 1, 2 veya 3 ile bitip bitmediğini kontrol etmeden önce. Bir mantık parçası A&B gerektiriyorsa ve P (B) = 0,1 iken P (A) = 0,9 ise kontrol edin Önce B, eğer değilse! A sonra! B (beğenmek if(myObject != null && myObject.someProperty == 1)) veya B değerlendirmek ( if(myObject != null && some10SecondMethodReturningBool())) için A'dan 9 kat daha uzun sürer .
  • Cevabını zaten bildiğiniz herhangi bir soru sormayın - Bir dizi "düşme" koşulunuz varsa ve bu koşullardan biri veya daha fazlası da kontrol edilmesi gereken daha basit bir koşula bağlıysa, asla ikisini de kontrol etmeyin bunlar bağımsız olarak. Örneğin, A gerektiren bir çekiniz ve A && B gerektiren bir çekiniz varsa, A'yı kontrol etmelisiniz ve eğer doğruysa B'yi kontrol etmelisiniz. Eğer! A, o zaman! A&&B, bu yüzden bile rahatsız etmeyin.
  • Bir şeyi ne kadar çok yaparsanız, nasıl yapıldığına daha fazla dikkat etmelisiniz - Bu, gelişimde, birçok düzeyde ortak bir temadır; genel bir gelişme anlamında, "ortak bir görev zaman alıcı veya becerikli ise, daha iyi bir yol bulmak için hem sinirli hem de bilgili olana kadar bunu yapmaya devam edin". Kod terimleriyle, verimsiz bir algoritma ne kadar çok çalıştırılırsa, onu optimize ederek genel performansta o kadar fazla kazanırsınız. İkili bir montaj ve hata ayıklama sembollerini alabilen ve bazı kullanım durumlarından geçtikten sonra en çok hangi kod satırlarının çalıştırıldığını gösteren profil oluşturma araçları vardır. Bu çizgiler ve bu çizgileri yöneten çizgiler, en çok dikkat etmeniz gereken şeydir, çünkü orada elde ettiğiniz verimlilikte herhangi bir artış çoğalır.
  • Daha karmaşık bir algoritma, ona yeterince donanım atarsanız daha az karmaşık bir algoritmaya benziyor . Algoritmanızın üzerinde çalıştığınız sistemin (veya bir kısmının) teknik sınırlarına yaklaştığını fark etmeniz gereken bazı zamanlar vardır; daha hızlı olması gerekiyorsa, daha iyi bir donanımda çalıştırarak daha fazla kazanç elde edersiniz. Bu, paralelleştirme için de geçerlidir; bir N 2 , N çekirdek yayınlandığında -complexity algoritması, görünüm doğrusal. Dolayısıyla, yazdığınız algoritma türü için daha düşük karmaşıklığa sahip olduğunuzdan eminseniz, "bölme ve fethetme" yollarını arayın.
  • Yeterince hızlı olduğunda hızlı - Belirli bir çipi hedeflemek için elle paketleme tertibatı olmadıkça, her zaman kazanılacak bir şey vardır. Ancak, el paketleme montajı İSTEMİYORSANIZ, müşterinin “yeterince iyi” dediği şeyi daima aklınızda bulundurmalısınız. Yine, "erken optimizasyon tüm kötülüklerin köküdür"; müşteriniz yeterince hızlı aradığında, artık yeterince hızlı olduğunu düşünene kadar işiniz bitti.

0

Optimizasyon hakkında endişelenmenin tek zamanı, çok büyük bir şeyle uğraştığınızı veya çok sayıda şey bildiğiniz bir şeyle uğraştığınızı bildiğiniz zamandır.

"Dev" tanımı, hedef sistemlerinizin nasıl olduğuna bağlı olarak değişmektedir.


0

Bir hata ayıklayıcı ile adım atmak daha kolay olduğu için iki satır sürümünü tercih ederim. Birkaç katıştırılmış çağrıya sahip bir hat daha zor hale getirir.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.