tifyty

pure Java, what else ?

Havi archívumok: január 2013

Spóroljunk a bájtokon

Anno a régi szép időkben papíron írtuk az assembly kódot. Volt egy laminált lapom, aminek a két oldalán ott voltak az opkódok hexában, és kézzel kellett kikeresni minden egyes utasításhoz a kódot hogy utána a hexa konzolon be lehessen vinni a gépbe. A relatív ugró utasítások offszetjét is kézzel kellett leszámolni. Harmadévben az egyetemen írtam is egy oktatófüzetet Z80 programozási gyakorlatok címmel, assembly mintapéldákkal, és magyarázatokkal. A füzetet az egyetemi nyomda sokszorosította. PDF, eMail? Ez a 80-as évek végén volt. A szöveg szerkesztéséhez a Tasword programot használtam. Emlékszik rá valaki?

Akkoriban azon versenyeztünk, hogy ki tud rövidebb programot írni egy adott problémára. Sok trükk volt arra, hogy hogyan lehet egy-egy bájtot megspórolni a programban. Olyan programot is írtunk, amelyik az ugró utasítás offset bájtját máskor végrehajtandó utasításként használta, attól függően, hogy éppen merre haladt a program futása. A decimális BCD korrekciós utasítást pedig egészen abszurd módon használtuk, hogy rövid, 16 bites osztó programot tudjunk írni.

Mostanában, mi programozók nem azzal vagyunk elfoglalva, hogy hogyan lehet bájtokat megspórolni, és ez jól van így. Én örülök ennek. Inkább sokkal magasabb szintű problémákra fókuszálunk, amelyeknek több értelme van. Az alacsony szintű problémákat megoldják a fordítók, betöltő programok. Mostanában van elég memóriánk, és olcsó. A Mac gépemben most 8GB memória van, ami 175ezerszer több, mint amennyi memóriája a ZX Spektrumnak volt. Ha ennyi ZX Spektrumot leraknánk egymás mellé az útra, akkor 61km hosszú lenne. A fordítók és az optimalizálók is tudják ezt, és nem azzal foglalkoznak, hogy a program legyen minél rövidebb futtatható formában. És ez jó. Általában.

Néhány nappal ezelőtt egy fórumon diszkusszióba keveredtünk azzal a tiszta kód gyakorlattal kapcsolatban, hogy egy metódus minden argumentuma legyen Java-ban final. Azt gondolom, hogy ez jó gyakorlat minden egyes argumentum elé odaírni a final kulcsszót, és tulajdonképpen a nyelv hiányossága, vagy tervezési hiba, hogy az argumentumok nem final változók alaphelyzetben. Ezt le is írtam, és erre válaszként azt kaptam, hogy ebben az esetben még egy lokális változóra van szükség, amibe átmásoljuk az argumentum értékét, és amit utána lehet módosítani, és ez memória pazarlás. Igen is és nem is. A JIT fordító a HotSpot JVM-ben majd jól kioptimalizálja. “Túl késő!” jött a válasz. Amikor a JIT optimalizál, akkor a byte kód már be lett töltve a néha bizony szűkös telefon memóriába. És a javac nem nagyon optimalizál, hiszen, mint ez már annyiszor említve lett: a túl korai optimalizálás minden házasság megrontója.

Hát már megint itt vagyunk? Takarékoskodunk a bájtokkal megint? Sajnos igen. A fordítók, és a többi hasonló szoftver eszközök a fő használati irányokra lettek kitalálva. Vannak ugyan olyan eszközök, mint a yguard, de nem biztos, hogy megfelelők az adott célra.

De ahogyan elmúlt a z80 bájt takarékos korszaka, el fog múlni ez is. Hamarosan már minden telefonban lesz annyi memória, hogy ne kelljen ilyen alacsony szintű problémákkal foglalkozni, és a programozók foglalkozhatnak a fontos dolgokkal. Csak éppen akkor majd jönnek a kevés memóriával rendelkező porszívók, villanykapcsolók, zuhanyrózsák és így tovább. Lehet, hogy egyszer, ha lelassul a fejlődés, akkor végleg eltűnik a memória mizéria. Talán. De akkor lesz más. Mondjuk sávszélesség. Majd le akarunk tölteni a személyes használatú űrhajónkra (lesz mindenkinek saját, mint most mobil) egy új szoftvert, és az űrhajó éppen két fényóra távolságra van, valahol a Jupiter környékén. Hand shaking, hibajavító algoritmusok, késleltetés… bájtok megint. Aztán ezt is megoldjuk, és akkor majd jönnek hasonló problémák a hiper szpészben, amit ma még kitalálni sem tudunk.

Mi a tanulság? Mindegy, hogy hogyan fejlődik a technológia, a trükkök időről időre visszatérnek. Talán kicsit más formában, de az alapprobléma megmarad: nem szabad az erőforrásokat pazarolni. És ez nem csak a programozásra igaz. Védd a fákat, egyél hódot! (angolul ez egy kicsit pikánsabban hangzik.)

Vizsga

Megöregedtem annyira, hogy már a fiam jár egyetemre, és vizsgázik. Sok éve én magam is tanítottam a BME-n, voltam egyetemi évek alatt is gyakorlat vezető, demonstrátor, és egyetem után is PhD. ösztöndíjasként oktató (-nak látszó ember, és nem féltek használni). Hogy volt-e jogom vizsgáztatni, vagy sem, azt nem tudom, de hacsak nem minősül háborús bűnnek, akkor el is évült a dolog. Amúgy a jegyeket sokszor nem én írtam alá ezért sanszos, hogy nem volt teljesen szabályos a dolog. De korrektnek, korrekt volt. Legalábbis akkor azt gondoltam, és ma is így emlékszem rá.

Később, már 2000 után volt egy saját tárgyam, amit ötödéveseknek adtam elő egy félévben Pongor Gyuri barátommal. Ez a tárgy a ScriptBasic architektúrájáról szólt, meg általában arról, hogy hogyan kell interpretált nyelvet készíteni. A fordító programok egyébként Gyurinak is a kedvencei voltak. Tőle tanultam először Java-t, beültem az óráira. A következő félévben kevesen jelentkeztek a tárgyra, nem indult, és mire megint őszi félév lett volna Gyuri teniszezés után kapott egy szívrohamot, és meghalt. A személyes honlapja ma is változatlan.

Ezzel persze nem ért véget az oktató tevékenységem, mert ha valaki oktató, akkor oktat (és nem tévesztendő össze a kioktatóval, aki kioktat). Tanítottam professzionálisan a Számalk-nál, és különböző projektekhez kapcsolódva saját cégben, és most is a jelenlegi munkáltatómnál is rendszeresen tartok tanfolyamokat.

És nem csak tanítottam, hanem vizsgáztattam is, mint említettem már annak kapcsán, hogy nem tudom jogos volt-e. És most is vizsgáztatok amikor jönnek ifjú (és kevésbé ifjú) titánok, akik szeretnének itt dolgozni a cégnél. A lényeges különbség, hogy a felvételi interjú során olyan emberek tudását kell felmérnem, akikkel ott találkozom először, míg oktatási folyamat lezárása során a vizsgázókat ismerem személyesen, hiszen tanítottam őket.

Amit először észrevettem, hogy ez egy lényeges különbség. Ha a tanítvány megbukik, akkor én is megbuktam: nem tanítottam meg jól, nem sikerült rávennem, hogy megtanulja a tárgyat, de legalábbis nem sikerült felkeltenem az érdeklődését. Ritkán az is lehet, hogy nem sikerült idejében észrevenni, és kideríteni, hogy az adott tárgy nem neki való. A felvételi interjún jön a jelölt, és lehet okos, vagy tökhülye: engem nem minősít. Ennek ellenére vidám vagyok, ha a beszélgetés alapján a jelöltet tudom javasolni, és szomorú vagyok ha nem. Tévedés ne essék: engem ezen nem mérnek, nem kapok se több, se kevesebb pénzt, elismerést akár továbbküldöm, akár elutasítom a jelöltet.

De az interjúk általában sikeresek. Legalábbis ez az érzésem, bár biztos nem lehetek benne. Hogy lehet az, hogy az interjú mindig sikeres? Ellátja a feladatát. Ha megfelel a jelölt, akkor mehet tovább. Ha viszont nem felel meg a jelölt, nem kompatibilis a tudása, gyakorlata és tapasztalata a pozícióhoz társított elvárásokkal, akkor neki és a cégnek is jobb, ha egy óra alatt ezt kiderítjük. Sokan megfeleltek. Hogy küldtem-e el olyant, aki jó lett volna? Remélem, hogy nem.

Az interjú, a vizsga stresszes dolog. Nekem kevésbé, a vizsgázónak inkább. Pedig a vizsgán nem dől el semmi. Furcsa, nem? Mire a vizsgára kerül a sor, addigra már minden eldőlt. A vizsgázó vagy tudja amit kell, vagy nem tudja. Csak akkor van tétje a vizsgának, ha a vizsgáztató rossz. Ilyenkor előfordulhat, hogy a rossz hangulata miatt kirúg valakit, vagy éppen fordítva: sikerül a vizsgáztatót becsapni. Az elsőre nagyon vigyázok: az értékelésem legyen minél objektívebb. Amennyire csak tudok objektív lenni (bár nem Nikon). A becsapni, pedig… lol

Azért elég kicsi az esélye, hogy valaki folyamatosan, több témakörben is be tudjon csapni a tudását illetően. Pedig van, aki megpróbálja. Kérdezek egy témakört, hogy beszéljen nekem arról a vizsgázó, és fél mondat után már 99%-ig biztos vagyok benne, hogy fogalma nincs a történetről. Még pár mondat, és már azt is tudom, hogy milyen kérdéseket tegyek fel, hogy a maradék egy százalék is meglegyen. De az az egy százalék baromi fontos. Volt rá példa, hogy feltettem ezeket a kérdéseket, és kiderült, hogy a vizsgázó ismeri a témát megfelelően, csak épp a verbális kommunikációs képességei hagynak kívánni valót maguk után. És volt fordítva is.

Beültem egy interjúra, ahol PIKIL módszertanhoz értő embert kerestünk. (PIKIL helyettesíthető tetszőleges betűszóval.) Azért kerestünk ilyen embert, mert kellett egy feladatra, és nem volt egyetlen egy PIKIL profi sem a cégben. Én viszont korábbi életeimben, mielőtt reinkarnálódtam volna Java programozóként a mostani helyemen, foglalkoztam PIKIL-lel, és így voltak transzcendens emlékeim, igaz még a PIKILv2 és nem a mostan divatos PIKILv3 módszertanról. Bejött egy ember, előadta, hogy ő mennyire ért a PIKIL-hez és mennyi tapasztalata van. Nagyon jól nyomta, és mivel interjún nem szeretek olyant kérdezni, amire nem tudom biztonságosan a választ (majd erre is kitérek, hogy miért) nem nagyon kérdeztem. De valahol motoszkált bennem valami kukac, hogy ez a manus csak dumál. Aztán feltettem neki egy kérdést, hogy az éppen diszkutált szituációban hogyan hozna létre egy TLA-t (tudod: three letter abbreviation, lehet bármi más). Öt percig mondta folyamatosan a különböző aspektusokat, de éreztem, hogy fogalma nincs róla, hogy miről beszél. De annyira jó volt dumában a manus, hogy nem voltam benne egészen biztos. Aztán húsz perccel később az interjú végén megkérdeztem tőle, hogy a PIKIL témakörben minek a rövidítése a TLA. És itt vége volt a történetnek. Erre nem lehet hablatyolni: tudod, vagy nem tudod. Természetesen nem tudta, és az sem tűnt fel neki, hogy korábban öt percet éppen “erről” beszélt. Szerencsére a felvételiztető kolléga, aki hivatalosan bírálta el az interjút tőlem függetlenül is, zsigerből ugyanarra a következtetésre jutott amire én: ennél az embernél teljesítmény nem lesz, de megtámadhatatlan magyarázat a miért nincs-re, az mindig. Tanulságos volt.

Miért ne kérdezz olyan kérdést vizsgán, amire nem tudod biztosan a választ? Mert a vizsga nem erre való. Nem vagyok sem orákulum, sem vátesz, hogy mindent tudjak. A vizsgázótól sem várom el, hogy mindent tudjon. Miért ne lehetne olyan kérdés, amelyikre nem tudom a választ? És egy jó szakmai partnerrel nagyon vonzó olyan területekre tévedni, ahol még nem hajózott az ember, és valami újat tanulni. A baj csak ott van, hogy a vizsgán van a vizsgázó, és van a vizsgáztató. És a vizsgáztató értékeli a vizsgát (rosszabb esetben a vizsgázót: hülye vagy fiam), és ez csak akkor működik, ha a vizsgáztató okosabb(nak tűnik), mint a vizsgázó. De a tudás az nem egy rendezett halmaz, inkább valami vektorféle. Nem lehet azt mondani, hogy Einstein okosabb volt, mint Napóleon, vagy a büfés Mari néni okosabb, mint Julika a takarítónő. Az egyik is ért valamihez a másik is, az egyik ebben jobb, a másik abban. Ha minden kérdésben okosabb vagyok, mint a vizsgázó, akkor nincs gond az értékeléssel: el fogja fogadni. Ez a tuti.

De mi van akkor, ha kiderül, hogy valamit ő tud jobban? Ha elég okos a vizsgázó, és megfelel, akkor nincs gond: miért ne fogadná el? A másik véglet se gond, amikor sajnos esélye sincs bármiben is okosabbnak lenni nálam a szakmánkban. Ez szomorú, mert ez legtöbbször azt jelenti, hogy nincs tisztában a saját képességeivel vagy az elvárásokkal. Ilyenkor az interjú hamar véget ér, és a maradék időt azzal szoktam tölteni, hogy segítek megérteni neki, hogy mi nem stimmel: mit kellene tanulnia, vagy ha hozzáállási probléma van, akkor a szoftver miért nem jó választás: menjen inkább menedzsernek, BA-nak ami megfelel a motivációinak.

A gond akkor van, ha a jelentkező valahol középúton van, éppen nem felel meg, és magasabbra értékeli tudását a valóságnál. Ő azt gondolja, hogy megfelel a tudása, de én mégis elkaszáltam. Egyszer futottam bele egy ilyenbe, aki az interjú után visszaszólt, hogy valami nem is úgy volt, ahogy mondtam. Kellemetlen volt. Nekem is, de biztos vagyok benne, hogy neki is. Jobb megkímélni őket is attól az élménytől, hogy “ő ugyan megfelelt, de egy nagyképű pöc…khendi alak kirúgta”. Mert ezt így éli meg, és még ekkor sem kap valós képet a képességeiről. (Deny fázisban van és sokszor ott is marad, míg Herr Alzheimer be nem kopogtat.) Valami oka volt, hogy kirúgtam. És nem a kommunikációs stílus, mert azt nem értékelem, bár biztos, hogy befolyásol. Szaktudás. Szóval jobb, ha minden egyes érintett dimenzió mentén okosabb vagyok. Biztonságosabb. És nagyon örülök, amikor olyan embert felvételiztethetek, akiről az az érzésem, hogy majd kollégává válva sokat tanulhatok tőle.

Aztán azért is stresszes egy vizsga, mert a végén úgy áll fel az ember, hogy ő semmit nem tudott, amit kérdeztek. Én is így éreztem, amikor ide felvettek. De mi ennek az oka? Egyszerűen a vizsgahelyzet specialitása: kérdezek valamit a vizsgázótól. Én tudom a választ, és nem is a válasz érdekel. Az érdekel, hogy tudja-e a választ. Ha eleget elmondott a témáról ahhoz, hogy biztos legyek benne, hogy tudja a témát elég mélységében, akkor minden további szó felesleges, csak viszi az időt. Ezért megállítom, és kérdezek mást. Na ez baromi frusztráló tud lenni. Ha észreveszem, hogy stresszel, akkor inkább hagyom tovább beszélni arról amiről tud a vizsgázó beszélni, és ha félbe is szakítom, akkor is “megdicsérem”, hogy ezt a témakört nagyon jól tudja.

A vizsga két részből áll: van egy elméleti tételsor, amiről kérdezgetek, beszélgetünk, és van egy feladat. Mindig más. Na jó, nem mindig más, de azért időnként cserélődnek a feladatok, mert valahogy kijut, hogy milyen feladatokat szoktunk feladni. Volt, aki el is szólta magát, hogy aszonta: “nem ezt a feladatot vártam, a haverom két hete nem ezt kapta”. Hát, ilyen az élet Babólcsán!

És milyen tanulságos a két rész egymáshoz való viszonya: van olyan aki nagy tapasztalatú, és utána nem tud megoldani egy algoritmikus feladatot. És van fordítva is: junior, kevés tapasztalattal, de remekül algoritmizál, és pillanat alatt átlátja a feladatot. És az is nagyon tanulságos volt, amikor az egyik jelentkező nem a “hivatalos” megoldást véste fel a táblára, hanem egy annál rövidebbet, érthetőbbet és még hatékonyabbat is. No lám! Fel is vettük.

Az is nagyon fontos, hogy az vizsga végeztével nem a vizsgázót kell értékelni, csak vizsgát. Nem mondhatom senkire, hogy “haver, te buta vagy! Hö! Há! Már mér?” Ez vitatható és nincs is értelme. A vizsga eredménye viszont az ami: megfelelő a mért tudás, vagy nem. Az a következő kérdés, hogy a valódi tudással milyen kapcsolatban van a mért tudás.

Még az egyetemen történt, hogy egy hallgató felvetette ezt a kérdést, és azt mondta, hogy nem igazságos, hogy a vizsga nem a tudást méri, hanem azt, hogy éppen akkor mit teljesített. Ott, tudva, hogy nem csak informatikát tanultak a hölgyek és urak válaszolhattam azt, hogy tanultak kvantummechanikát, tehát tudják, hogy azt, amit mérni szeretnénk, még elméletileg sem lehet pontosan megmérni, mert beleavatkozunk a rendszerbe. Méréselméletből pedig tudhatják, hogy a gyakorlati mérések során valami mást mérünk általában, mint amire kíváncsiak vagyunk. Áramerősség helyett mágneses tér által eltérített mutató kitérését, nyomás helyett higanyoszlop magasságát stb. Azt szeretjük, ha a mért dolog és amire kíváncsiak vagyunk összefügg. De már akkor is szerencsések vagyunk ha a két dolog korrelál. A való életben a két dolognak nagyon sokszor semmi köze egymáshoz. Nem azt büntetik meg aki veszélyesen vezet, hanem azt aki gyorsan.

De ha a vizsgáztató megfelelő, akkor a mért dolog, a vizsga eredménye, és az ismerni kívánt dolog, a tudás korrelál.

Logger, logger.. te miért jársz ide?

Mindegy milyen loggert használunk minden egyes osztálynál a logger inicializálása fájdalom a szamárban (gy.k: pain in the donkey). Mert lehet a logger példányváltozó, és tudom, tudom, hogy premature optimization meg társai, de akkor is pazarékoskodunk az erőforrásokkal. Persze akkor lehet IOC konténerből injektálni. De azért csak lehetne az a nyomorult static változó, és mindegyik loggoló frémvörk esetében a logger neve az osztály neve. Ami már csak ezért is bosszantó, mert kénytelen vagyok leírni még egyszer az osztály nevét, egy sorral az osztály neve alatt.

public class PurchaseOrder {
	private static Logger log = Logger.getLogger(PurchaseOrder.class
			.getCanonicalName());

Akkor most programozunk, vagy hímzünk? Kódot írunk, vagy sormintát? (Mondjuk találkoztam már olyan programozóval, akinek a lelkétől nem állt távol a sorminta.)

Persze, persze tudom: ez legyen a legnagyobb problémám és ez legyen az ami miatt inszomniásan forgolódom éjszaka az ágyamban. First world problem.

Eleddig nem is vettem komolyan ezt a fajta nyűglődést, mert azért lássuk be: ez csak nyűglődés. Írtam egyszer egy annotációs interfészt is, amelyik alapján egy osztály szépen betölti a statikus mezőbe refleksőnnel a loggert, de ez inkább csak ujjgyakorlat vala. Komoly projektben nem használtam, mert nem lövünk ágyúval verébre, műveltebben szólva aquila non captat muscas. (Ennek a latin szólásnak a népszerű félrefordításait most kihagyom, túl olcsó poén lenne.)

aztán jött a Java 7 és a BA…

…és jött vele az invokedynamic. Miért érdekes ez? Hát a loggoláshoz ennek magának nincs sok köze, ilyen kódot nem is generál a javac, ám ami ezzel együtt jött járulékos veszteségként a JDK-ban, az többek között a MethodHandles osztály. Ezzel egy MethodHandles.lookup().lookupClass() hívással hozzájutunk az éppen futó osztály objektumhoz statikus környezetben is. Itt a mintakód:

package dustin.examples.methodhandles;

import java.lang.invoke.MethodHandles;
import java.util.logging.Logger;

/**
 * Demonstrating use of MethodHandles with java.util.logging.
 * 
 * @author Dustin
 */
public class MethodHandlesLoggerJavaUtilLogging {
	/** Use Java 7 MethodHandles to get my class name for logger. */
	private static final Logger LOGGER = Logger.getLogger(MethodHandles
			.lookup().lookupClass().getCanonicalName());

	public static void main(final String[] arguments) {
		final String msg = "Hello World: Using MethodHandles for Class to associate with java.util.logging logger.";
		LOGGER.info(msg);
	}
}

Akit részletesebben érdekel, az megtalálja az eredeti cikket a JavaWorld oldalain.

Csak nehogy úgy járjatok, hogy elkezded olvasni és azt veszed észre, hogy már többet tudsz az inkovedynamic-ról, mint amennyit valaha is tudni akartál.

Aki először beírja kommentbe, hogy mi az a BA, az megkapja tőlem a hét geekja megtisztelő címet.

[E] Problem with Java Security


This article about my thoughts about the currently emerged security issue related to Java. Not too technical and only general thoughts.

Recently a new vulnerability of the Java runtime emerged. You can have a look at http://nakedsecurity.sophos.com/2013/01/10/protect-yourself-against-latest-java-zero-day-vulnerability-now-maljavajar-b/ and http://nakedsecurity.sophos.com/2013/01/11/apple-and-mozilla-just-say-no-to-java/ and also http://www.pcworld.com/article/2025160/its-time-to-rewrite-java-from-scratch-security-expert-says.html

The latest article suggest not less than rewriting the security part of the Java system. The title exaggerates to rewriting Java as a whole. And this is one of the major, though not the largest problem with Java security that I will discuss in this article: journalism. But we will see that later. The first question I want to talk about is why this issue came up now and not earlier. Similar vulnerabilities were discovered in Java last year and that time I could not see articles stating that Java generally is insecure.

You can think of this process of awakening like the two stages of incident management and problem management that may sound familiar if you know ITIL. When the problem first appeared it was fixed. That is the most important thing because many businesses depend on Java and if Java turns to be unusable as a whole that costs a lot of money. Really a lot. Fortunately there is marginal probability to find Java insecure without reasonable way to fix the issue. Even if the issue is fixed the vulnerability costs us money. There can be security breaches during the period between the vulnerability discovery and the time the fix is applied. Applying the fix is also cost for many businesses and institutions, and those are not happy spending money for something that does not lead to higher income. Thus we raise the question: “this happened this time, but can we trust your technology that it will not happen in the future?”. To find the answer is problem management.

Institutions like men working in support are lazy. After all we are programmers down in our heart and programmers are lazy. Actually programmers have to be lazy to be good in their job. Because of that support people say “this was a one time problem, we fixed it, but it is not likely that there are more such bugs in the system”. Wrong. Totally wrong this time and, my personal opinion is that such answer and attitude is totally wrong at any time. If you find a cockroach under your bed, it is a vain hope that it was a lonely warrior. There will be more and you better call bug hunters. As for Java it became obvious this year on January 11, 2013. A similar bug to the one appeared a year ago emerged again. Dear ORACLE: what are you doing with it now? What is your answer to the “problem management” question. What will you do so that it does not happen any more time? We wait for the answer not being ready from the vendor side. In the meantime we may speculate what the answer can be. There are technical aspects to anticipate the answer as well as industry answers.

In this article I would like to express my thoughts on the topic. Before getting into the details I want to state that I am not a security expert. Even not being one you can not avoid dealing with security issues if you work for the IT industry for more than 20 years, which I do.

problem #1

Nothing is prohibited…

The first and most technical issue with Java considering security that the language and the runtime are rather permissive. When you start a Java application with some security context (discussed a bit later) you can do anything unless the security context forbids that. This is not a secure approach. The secure approach is to forbid everything that is not allowed. Java is just the other way. Why?

This is because secure systems are hard to use. Their use costs a lot because of the hardness of the use. To set the permissions properly so that our business functions smoothly you have to discover your business processes and set the permissions to that everybody can do what it needs to do to operate the business. Having a more exhaustive map of the business processes costs way more than the permissive approach. If you trust the players at your company you can use the permissive approach. There are some things that are definitely forbidden: for example your secretary can not give herself raise. On the other hand she can occasionally handle parcels arriving to the company when you are away. If the company controls are permissible there is no need to say that: it is common sense. When the players can not be trusted you need to be restrictive. You can replace a secretary you do not trust but you can not replace the Internet users. They, or rather we are the people of the earth with our human nature. Crime, fighting, war, on-line felony are inherent part of human nature. Live with it!

This control issue goes down to every aspect of your company from key distribution (I mean keys made of metal to doors) down to software, even Java. Java is permissive.

problem #2

Way too complex

When you start a Java application the security context that is meant to control the access to various resources is null. This is not the case for Java Applets, but I will talk about that later. It is possible to set the security context programmatically and most application servers do that. Opps… sorry. They actually don’t. They can be configured to do that. By default they do not. Why? Because it would be so difficult to use them if they forced the administrators to configure the security that the majority of their user base would be nonexistent. Security is complex. This is the unfortunate fact but it is not because of Java. It is a general fact. I have never seen any production installation of Tomcat configured with non null security context.

For applets this is not the case. Applets run in a sand box of the Internet browser and the Java programs are allowed to mangle the sand only in the box. The sand is a metaphor an in this case means files to be read, written, executed, ports to listen on, memory objects out of the process space of the applet thread and other operating system resources. The Java system, more specifically the JVM that executes the code uses these resources on behalf of the Java programs and it does not check security (I am not absolutely sure about that, but the depth I dig into showed that). Java code is supposed to be blocked by the JDK routines to reach that level. And there are many functions that have to be controlled by security. It is like a house that has many entrances. One for the house master, one for the kids, one for the maid and there is even some hole on the wall for the mice. Each one except the forgotten ones has guards. Some are good, some have some faults as we see recently. One is fixed does not guarantee there isn’t another somewhere else. Even these doors are connected with a complex maze of tunnels. Way too complex.

If you want security controlled you need something as simple as possible. The more complex the more bugs there can be. Have only one door and simple rules.

Forget Applets

The easiest solution to this problem on the problem management level is what Apple and Firefox did. Switch off Java for the browsers. Applets are Java programs that intended to give client side functionality to browsers. The idea was perhaps too early, or just became the victim of the Sun vs. MS war. It alone would be a long post to discuss the reasons. Whatever: Java applets are rarely used and are generally considered legacy. Most of the functionality that was meant to be solved using applets are solved now by JavaScript that developed enormously during the recent years. Even though applets are still around and the browsers support applets. There are a very few applications that need them. I personally know two. One is a home banking application. Terminate your account and contract a different bank! The other one I know and recently faces is Atlassian JIRA that uses applet to ease the upload of screen shots. You can upload the JPG file instead. No problem.

Thus my suggestion to solve the issue on the problem management level is to forget applets once and for all. At least that is the way we are heading.

problem #3

Scripting languages on the road

Would forgetting applets solve the issue? For the current issue yes, but again: this is incident management. From a different angle the issue remains. Java is not secured inside. If we want to use Java as language and runtime environment in which some of the players are not trusted then the architecture is not appropriate. I do not see such use in addition to applets at the moment but with the dawn of scripting languages and their viral spread on JVM raises similar issue again:

Soon we will want to run scripted programs inside the JVM. These programs will source from untrusted players who extend the functionality of the program. This is as blog engine’s HTML pages were extended by the HTML text of the blogger and the commenter. Does WordPress trust me that much? I doubt. Thus they make counter measures so that I can not inject XSS, click jacking and other naughty things (or can I?). We will create/use applications that allow the users to write simple scripts to perform operations that are tailor made and that are not readily available from top of the head of the application designers.

This situation is similar to the applet. In case of the applet the outside world has to be protected from untrusted code written in Java. In case of scripts the outside world including the JVM and Java code running in the application has to be protected from the scripting solution. Many of the scripting implementation do not go that way. Programs written in JRuby, Scala, Jython and so on are compiled to JVM byte code and run just as they were written in Java. The Java architecture however is far from being ready to protect one piece of Java code from the other running in the same JVM. There is no internal access control in the JVM.

We have a long way to go.

problem #4

Journalism

The aim of journalists is to gather as many readers as possible. Even I, writing this article, do it to have many readers. Not for money, though. To have readers the article has to be interesting and appealing. If the truth is not appealing enough a bit of color, slipping a bit the facts does not harm. Or does it?

Yes, it does, especially in the arena of security. People like to feel threatened. That is why horror movies and thrillers exist. That is the reason most of the people read security related articles. It helps the soul reassuring ourselves. The side effect is that some of the people not only shivers reading the articles but partially understands some of the statements. Not all, only some of them. And most of the people are not knowledgeable enough to judge the statements. If there are some bend in the facts, some statements slip then the perception may diverge from reality 180 degree. Just going the other way around.

The articles say that Apple and Firefox “say no to Java”. Actually they say no to Java applets and Java application started right from the web. Apple actually does that for all applications anyway unless you configure security setting to differ from default.

The title of the other article says: “It’s time to rewrite Java from scratch, security expert says”. If you read the article it talks about the security part of Java.

The casual reader from these will deduct that Java is wrong. That is not the case and if you believe something that is different from the fact you get poorer. You make decisions whether you want to use Java in your company or become a Microsoft shop based on your knowledge. Thus those exaggerations are good to the competitors only. Not for the users of the technology and at the end of the line the customers of the users of the technology.

Summary

Consider these as random thoughts only. I wanted to be as precise as I could, however security and Java security is not my major. These are just some spots on the whole issue and many areas remain darkened. Feel free to discuss what you agree or see my approach wrong.

My personal area that is a bit related to this area is ScriptBasic for Java, which is a scripting language NOT compiled to Java byte code, but rather interpreted by Java code (thus it actually is slower) and can be fully controlled by the embedding application what scripts can do. It was designed to provide a mean to application programmers to provide a tool to users to extend applications embedding the interpreter in a way that can not harm the application.

Enough of me. Now: what are your thoughts?

Nem jön álom a szememre

Van a Thread osztályban egy sleep() metódus. Statikus, szál példány nélkül meg lehet hívni, és arra való, hogy aludjon egy kicsit a szál. Kb annyi miliszekundumot, amennyit megadtunk argumentumként. De ugye egy miliszekundum nagyon hosszú idő, az alatt sok százezer utasítást is végre tud hajtani a processzor. Nem biztos, hogy ilyen hosszan altatni akarunk egy szálat, nem Csipkerózsika az.

De nem is kell, hiszen ott van a másik statikus metódus, neve szintén sleep, testvére az elsőnek, két argumentummal. Az első argumentum továbbra is a miliszekundumok száma, a második pedig a nano szekundumoké. Így már nanoszekundum pontossággal megadhatjuk, hogy mit szeretnénk, mennyit aludjon a szálunk.

És valójában mennyit fog? Hát vagy annyit, vagy kevesebbet, vagy többet. Nincs semmire garancia. Ahogy meghívhatod a System.gc()-t is. Az is csak annyit mond, hogy ezzel a hívó kifejezte azon véleményét, hogy egy kis szemétgyűjtés éppen mehetne. Hogy megy-e? Azt majd a VM eldönti. Olyan ez, mint a szomszédaim a panelban, akik mindig jó zenét hallgatnak. Akár tetszik nekik, akár nem. A programok is mindig jókor gyűjtik a szemetet, a VM megszavazza, mikor. Hát az alvással is így van. Így aztán, amikor OSX alatti Java 7 JDK-ból megláttam az alábbi metódust, csak elcsodálkoztam. Nem gondolom, hogy bug lenne, hiszen a specifikációt teljesíti: vagy aludni fog, vagy nem. Vagy annyit, vagy nem. Vagy többet, vagy kevesebbet. De azért…

public static void sleep(long millis, int nanos)
    throws InterruptedException {
        if (millis < 0) {
            throw new IllegalArgumentException("timeout value is negative");
        }

        if (nanos < 0 || nanos > 999999) {
            throw new IllegalArgumentException(
                                "nanosecond timeout value out of range");
        }

        if (nanos >= 500000 || (nanos != 0 && millis == 0)) {
            millis++;
        }

        sleep(millis);
    }

A kód review mértékegysége a WTF per metódus. Azért a JDK-t olvasva is elsül egy-két WTF.

2012 in review

Elkészültek a 2012 évre a blog statisztikái. A képre kattintva lehet ezeket megtekinteni.

Érdekes, hogy pont a Többszörös öröklődés az a cikk, amelyiket a legtöbben olvasták. (És most, hogy ide belinkeltem, egy csomóan újra megnézik, tehát torzul a statisztika.) Én azt gondoltam, hogy nem ez a legérdekesebb, hanem más cikkek. De hát nem csak arról szól ez a blog, hogy az olvasók okuljanak: én még többet tanulok belőle.

Talán nem meglepő, hogy a legtöbb látogató Magyarországról jött a blog-ra. Bár, hogy ennek mi lehet az oka…

És végül, de nem utolsó sorban köszönöm a TOP kommentelőknek, hogy aktívan hozzájárultak 2012-ben a blog sikeréhez. És siker alatt nem azt értem, amit a statisztika mutat, hanem ami a statisztika mögött van, vagyis Ti.

BUÉK.

Gyengék vagyunk, puhák vagyunk, vagy nem is vagyunk

Egy korábbi bejegyzésben megnéztük, hogy hogyan néz ki a ThreadLocalMap és láttuk, hogy az Entry rész osztály kiterjeszti a WeakReference osztályt, de nem ástunk bele mélyebben, hogy mi is az. És hát főleg nem másztunk bele abba, hogy mi is az a SoftReference és pláne a PhantomReference.

A legtöbb, amit még gyakorlott és sokat (de nem eleget) látott Java programozóktól hallottam az, hogy ezek olyan referencia osztályok, amin keresztül el lehet érni objektumokat, addig, amíg a GC azokat össze nem gyűjti, és ezek a referenciák nem gátolják meg a GC-t, hogy összegyűjtse a hivatkozott objektumokat.

Azon túl, hogy ez az ismeret elég halvány, és maximum ahhoz használható, hogy ne lepődjünk meg, és szaladgáljunk sikoltozva, mint egy kislány, aki egeret látott a kamrában, amikor meglátjuk ezen osztályok valamelyikét egy keretrendszerben, de még csak nem is igaz: a fantom referencián keresztül nem lehet elérni az objektumot. (He? Se nem gátolja meg, hogy a GC összegyűjtse, se el nem érhető rajta keresztül, akkor meg minek van? Na majd meglátjuk jól.)

Mik ezek a referenciák?

Mielőtt ezekbe beleásunk először azt nézzük meg, hogy egyáltalán mi is az a Reference interfész amit mind a három referencia osztály implementál? Nos ez egy olyan interfész, amelyik egy másik objektumra való hivatkozás kezelését teszi lehetővé. Négy metódusa van:

  • clear()
  • enqueue()
  • get() és
  • isEnqueued()

A hivatkozott objektumot beállítani nem lehet, azt az implementációk konstruktor argumentumának kell átadni. A clear() törli a referenciát, a get() pedig visszaadja a hivatkozott objektumot (vagy nem). Ami igazán érdekes az az enqueue(). Ezt a metódust meghívhatjuk magunk is, de valószínűleg nem mi fogjuk meghívni, hanem a futtató VM. Legalábbis a puha, gyenge és fantom referenciák esetében amikor egy hivatkozott objektumot összegyűjtött és ledarált a GC, akkor a JVM meghívja az objektumra hivatkozó Reference objektum enqueue() metódusát. És ilyenkor a referenciát (már nem) hordozó objektum (nem amit a GC már begyűjtött, mert ugye, az már nincs is) bele fog kerülni egy ReferenceQueue-ba. Már, ha ilyent átadtunk a referencia létrehozásakor a konstruktornak. És abba, amelyiket átadtuk a létrehozás során.

Ilyen módon kaphatunk értesítést arról, hogy egy korábban létrehozott objektumot a rendszer begyűjtött és ledarált.

A puha és a gyenge referencia esetén van olyan konstrutor, amelyiknek csak a hivatkozott objektumot adjuk át paraméterként. A fantom referencia esetében csak olyan van, ahol a hivatkozott objektum mellett egy referencia sort is megadunk. Másnak ugyanis nem nagyon lenne értelme. A fantom referencia ugyanis null értéket ad vissza a get() meghívásakor, még akkor is ha a hivatkozott objektumunk vígan teszi a dolgát, és még sejtése sincs arról, hogy egyszer majd eléri a végzet.

És akkor most, hogy már kicsit belekapkodtunk, nézzük meg szisztematikusan, hogy mi is a három referencia típus, és utána azt is, hogy melyik mire jó. Majd pedig a végén örvendezzünk, hogy milyen jó, hogy mindezzel csak nagyon ritkán kell foglalkoznunk, mert hogy a keretrendszerek írói helyettünk már foglalkoztak ezekkel a dolgokkal!

A SoftReference egy olyan referencia, amelyiknek a get() metódusa visszaadja a hivatkozott objektumot, ha az még létezik, és a GC a hivatkozott objektumot garantáltan nem fogja begyűjteni amíg van rá legalább puha referencia, csak akkor, ha enélkül OutOfMemoryError lenne. Ebben az esetben viszont a puha referenciák egy részét, vagy mindet figyelmen kívül hagyja, és a hivatkozott objektumokat a GC ledarálja. Természetesen, ha a puha referencián kívül van rendes, erős referencia az objektumra, akkor a GC nem fogja kihúzni alólunk az objektumot.

A WeakReference is hasonló, de ebben az esetben a GC-t nem érdekli, hogy van-e fenyegető OutOfMemoryError lehetőség vagy nincs. Begyűjti (vagy nem) a hivatkozott objektumot (saját belátása szerint), amennyiben nincs rá élő puha vagy erős referencia pontosan úgy, mintha nem is lenne rá gyenge referencia.

Mind a két referencia esetében a get() metódus null értéket ad vissza, ha az objektum be lett gyűjtve és már nem létezik.

A PhantomReference abban különbözik a gyenge referenciától, hogy a get() metódus akkor is null értéket ad vissza, ha az objektum még él. (Ezt mondtam már, azt hiszem.)

A ReferenceQueue referenciákat ad vissza. Három publikus metódusa van, amelyek arra szolgálnak, hogy megnézzük, hogy van-e benne elem, illetve, hogy kivegyünk belőle egy referenciát.

Mire valók ezek a referenciák?

Soft Reference

A puha referencia tipikusan arra való, hogy objektumokat cache-ben tartsunk, de ha nincs elég hely, akkor ne akadályozzuk meg, hogy a GC kidobálja ezeket az objektumokat. Vagy nem?

Hát sok mindent lehet csinálni, például péppé lehet verni anyóst golfütővel, de ahogy a golfütőt sem arra találták ki, a puha referencia sem erre való. Ennek ellenére mégis erre használják nagyon sokan, de erről majd egyszer talán egy másik poszt. Most csak annyit, hogy a cache elemek élettartamát ne bízzuk a véletlenre.

No de akkor mire való a puha referencia? Nézzük meg a következő példát:

package com.verhas.puha;
import java.io.UnsupportedEncodingException;
import java.util.LinkedList;
import java.util.List;
import junit.framework.TestCase;
import org.junit.Test;
public class PuhaVagyJeno extends TestCase {
	private boolean weNeedIt() {
		return true;
	}
	private String fetchStringFromStore() throws UnsupportedEncodingException {
		return new String( new byte[100000],"utf-8");
	}
	@Test
	public void testOutOrMemoryError() throws Exception {
		List<String> results = new LinkedList<String>();
		while (weNeedIt()) {
			results.add(fetchStringFromStore());
		}
	}
}

A weNeedIt() és a fetchStringFromStore() helyébe a való életben képzeljünk valami olyant, ami valamilyen adatbázisból vagy máshonnan olvas adatot, és időről időre előfordulhat, hogy olyan sok sort akar beolvasni, amire már nincs elég memória. Mi történik? Természetesen elfogy a memória. Mit lehet tenni? Maximum elkapjuk az OutOfMemoryError-t, de ezzel az erővel a programunk az AIDS-et is elkaphatja: hogyan kezeled, amikor éppen nincs is memória?

Természetesen akkor sem lesz végtelen memóriánk, ha ügyesen puha referenciát használunk, de legalább lesz esélyünk kezelni a helyzetet:

package com.verhas.puha;
import java.io.UnsupportedEncodingException;
import java.lang.ref.SoftReference;
import java.util.LinkedList;
import java.util.List;
import junit.framework.TestCase;
import org.junit.Test;
public class MegPuhabbVagyJeno extends TestCase {
	private boolean weNeedIt() {
		return true;
	}
	private String fetchStringFromStore() throws UnsupportedEncodingException {
		return new String(new byte[100000], "utf-8");
	}
	@Test
	public void testOutOrMemoryError() throws Exception {
		SoftReference<List<String>> ref = new SoftReference<List<String>>(
				new LinkedList<String>());
		List<String> results;
		while (weNeedIt()) {
			String s = fetchStringFromStore();
			results = ref.get();
			if (results == null) {
				// ooops... no memory, our linked list was already released
				return;
			} else {
				results.add(s);
			}
			results = null;
		}
	}
}

Mi történik? Amikor elfogy a memória, és megpróbálja lefoglalni a memóriát az új String számára, beindul a GC és felszabadítja a láncolt listánkat. Két fontos dolgot kellett a kódban átalakítani, azon kívül, hogy a puha referenciát használjuk:

Az egyik, hogy a results változót lenullázzuk. A GC ugyanis nem tudná ledarálni a láncolt listát ha az erős referenciánk a results változóban megmarad. Ez még akkor is igaz lenne, ha a results változó szkópjából kilépünk. A GC ugyanis nem tud róla, hogy egy lokális változó még elérhető-e, látható-e a metódus éppen futó részében. Ez Java szintű dolog, a GC meg JVM szinten, bájt kódon fut, és ez nem látszik a bájt kódban, ez nyelvi elem.

A másik, hogy az új string létrehozását ki kellett emelni egy olyan sorra, ahol a results értéke éppen null.

Így már nem kell elkapnunk az OutOfMemoryError-t. Jeleztük a puha referenciával, hogy mit dobjon ki a léghajóból (asszony marad, anyós megy), és amikor kidobta, akkor nem hibát dob hanem széttárja a kezét és hiába kérjük tőle a jó kis láncolt listánkat halkan csak annyit mond: null. A láncolt listádnak annyi lett, öregem. Viszont van elég heap-ed, hogy megjeleníts egy hibaüzenetet a felhasználó felé: “próbálkozz máskor, amikor kevesebben használják az App szervert és több memória jut a lekérdezésedre.”

Weak Reference

A gyenge referencia használatára már láttunk példát a ThreadLocalMap osztályban. Egy olyan map-et hozott létre, amelyikben meg lehetett keresni egy objektumot, de nem akartuk, hogy a GC csak azért ne tudja ledarálni az objektumot, mert benne van a map-ban. Ha meghalt, meghalt. A golfütőt jól eldugjuk, és túltesszük magunkat rajta.

Ami még érdekes lehet ebben a témakörben, hogy ilyen map-et nem kell nekünk magunknak implementálni: van ilyen. Úgy hívják, hogy HashMap. Hé!!! Nem WeakHashMap-et akartál írni?

Bizony nem!

A WeakHashMap egy olyan map, amelyik a kulcs objektumokra tart gyenge referenciát. Ha az értékekre kell gyenge referencia, akkor HashMap helyett HashMap-t kell használni. És persze oda kell figyelni, amikor egy olyan referenciát kapunk vissza, amelyiknek a get() metódusa null-t ad vissza.

A WeakHashMap azonban nem ilyen egyszerű, az nem egy HashMap. Az ugyanis referencia objektumokat használna kulcsnak. A WeakHashMap viszont a mi eredeti objektumainkat használja kulcsként, csak éppen nem tart rájuk erős vagy puha referenciát. Csak gyengét, és ha a referencia mögül eltűnt a hivatkozott objektum, akkor ki is takarítja a bejegyzést.

Phantom Reference

Na ez a legérdekesebb. Mire való a fantom referencia? Se meg nem védi a hivatkozott objektumot a begyűjtéstől, se el nem lehet kérni tőle. Nos akkor mire való?

Arra, amire egyébként a puha és a gyenge referenciát is lehet használni, hogy a programunk értesítést kapjon arról, amikor egy objektumot a rendszer begyűjt. Ehhez létre kell hoznunk egy ReferenceQueue-t, és amikor létrehozzuk a referenciát, akkor a konstruktorban meg kell adnunk ezt a referencia sor példányt:

package com.verhas.fantomas;
import java.lang.ref.PhantomReference;
import java.lang.ref.Reference;
import java.lang.ref.ReferenceQueue;
import java.util.HashSet;
import java.util.Set;
public class Fantomas {
	public static void main(String[] argv) throws Exception
	{
	    Set<PhantomReference<byte[]>> refs = new HashSet<PhantomReference<byte[]>>();
	    ReferenceQueue<byte[]> queue = new ReferenceQueue<byte[]>();
	    for (int i = 0 ; i < 10000 ; i++)
	    {
	        PhantomReference<byte[]> ref
	            = new PhantomReference<byte[]>(new byte[100000], queue);
	        System.err.println(i + ": created " + ref);
	        refs.add(ref);
	        Reference<? extends byte[]> r2;
	        while ((r2 = queue.poll()) != null)
	        {
	            System.err.println("cleared " + r2);
	        }
	    }
	}
}

Ez egy nagyon egyszerű mintapélda. Nagyon sok, százezer bájt hosszú tömböt hozunk létre, és csak fantom referenciákat tartunk meg ezekre az objektumokra. Ebben a pillanatban ezek az objektumok azonnal begyűjthetővé is válnak, és egy idő után a GC be is fogja gyűjteni őket.

A referencia létrehozásakor átadunk a konstruktornak egy ReferenceQueue sort, és amikor a begyűjtés megtörtént, akkor a fantom referenciák megjelennek a queue sorban.

Ha ezt a kis programot elindítjuk mondjuk egy

java version "1.7.0_07"
Java(TM) SE Runtime Environment (build 1.7.0_07-b10)
Java HotSpot(TM) 64-Bit Server VM (build 23.3-b01, mixed mode)

rendszeren -Xmx12m paraméterrel (amelyik igencsak aprócska heap méretet enged meg), akkor látni fogjuk, hogy a létrehoz elemeket, majd pedig egyszer csak egy csomagban megjelennek ezek a referencia elemek a queue-ban, utána fut tovább a program, megint létrejönnek elemek, majd megint beindul a GC és minden elem felszabadul, és kb. 100 és 200 cikluslefutás között egyszer csak beüt az OutOfMemoryError. Ennek az az oka, hogy a fantom referenciák is elfoglalnak valamennyi helyet, és ezeket nem dobtuk el. De miért tettük bele a fantom referenciákat a Set-be? Nem használjuk sehol.

De igen: arra használjuk, hogy a fantom referencia objektumokra legyenek erős referenciáink, és a GC ne dobja ki a fantom referencia objektumokat a hivatkozott objektumokkal együtt. Ha ugyanis ezt tenné, akkor a GC után/során nem lenne amit a queue-ba bele tudna rakni, és nem is rakná bele. Viszont ha már belekerült a queue-ba és ki is vettük onnan, akkor ki lehet venni a Set-ből is egy

refs.remove(r2);

sorral, és ezzel nagy valószínűséggel elkerüljük a memória elfogyását. (Azért 12MB heap-pel nagyon sokat ne reméljünk. Hol van már a ZX Spektrum 48KB, vagy a 640KB mindenre elég!)

És akkor mielőtt nagyon boldogok lennénk a fantom referenciákkal, le kell, hogy lombozzam a lelkesedést: nincs rá garancia, hogy a fantom referencia belekerül a queue-ba. Csak akkor fog belekerülni, ha a hivatkozott objektumot a GC ledarálta. Ebből a szempontból pontosan ugyanolyan helyzetben vagyunk, mint finalize metódussal, amire eleddig még egyetlen értelmes példát sem láttam, hogy mire lehetne használni (marad a van, de ne piszkáljuk).

De ha valaki mégis talál ilyen feladatot, akkor valószínűleg jobban jár, ha nem az objektum finalize metódusát hívja, hanem inkább kezel (akár aszinkron szálon) egy ReferenceQueue-t. Miért?

  • Finalizer egy olyan objektumon fut, amit a szemétgyűjtő már kijelölt szemétgyűjtésre, és olyan állapotban van, amelyik … szóval már nem nagyon kellene vele semmit csinálni.
  • Ha véletlenül sikerül egy új erős referenciát létrehozni erre az objektumra, akkor az objektumot nem tudja begyűjteni a GC, de ettől még nem kerül vissza élő állapotba az objektumunk: zombi lesz. Ha újra elfogy minden erős referencia, akkor a GC megtalálja és ledarálja, de már nem fogja újra meghívni a finalizer-t.
  • A JVM sokszor egy szálon, egymás után futtatja a finalizer metódusokat, de ha van is több szál, akkor is, az fogja, de legalábbis befolyásolja a GC-t.
  • Amikor a finalizer fut, akkor tipikusan kevés a memória, hiszen elindult a GC, és mi másért indult el, mint azért, mert kevés a memória.

Ha azonban van egy referencia sorunk, akkor ezek a problémák nincsenek.

Összefoglalás

Ez egy eléggé száraz, hosszú, és tömény cikk lett. Ebből is látszik, hogy nem szeszes ital, mert abban ami tömény, az rövid. Viszont körbejártunk valamit, ami tapasztalatom szerint sokak számára nem világos.

A bejegyzést a cikk alapján írtam. Az eredeti cikkben vannak részek, amelyeket itt nem részleteztem, néhány példát leegyszerűsítettem, és vannak olyan témák (az se egy rövid cikk) amelyeket itt kihagytam.

És cikkírás közben is sokat tanulok.