Java: пул строк сохраняет строковые литералы, которые [дублируют]

Если вы пытаетесь зарегистрировать все ошибки, убедитесь, что вы сохранили строку Task.WhenAll в своем коде, многие комментарии предполагают, что вы можете удалить ее и дождаться отдельных задач. Task.WhenAll действительно важна для обработки ошибок. Без этой строки вы потенциально оставляете свой код открытым для незаметных исключений.

var catTask = FeedCat();
var houseTask = SellHouse();
var carTask = BuyCar();

await Task.WhenAll(catTask, houseTask, carTask);

var cat = await catTask;
var house = await houseTask;
var car = await carTask;

Представьте, что FeedCat генерирует исключение в следующем коде:

var catTask = FeedCat();
var houseTask = SellHouse();
var carTask = BuyCar();

var cat = await catTask;
var house = await houseTask;
var car = await carTask;

В этом случае вы никогда не будете ждать houseTask или carTask. Существует 3 возможных сценария:

  1. SellHouse уже успешно завершен, когда FeedCat не удалось. В этом случае вы в порядке.
  2. SellHouse не является полным и в какой-то момент не работает с ошибкой. Исключение не наблюдается и будет возвращено в финализацию.
  3. SellHouse не является полным и содержит в нем ожидания. В случае, если ваш код работает в ASP.NET, SellHouse завершится с ошибкой, как только некоторые из ожиданий будут завершены внутри него. Это происходит потому, что вы в основном сделали огонь и amp;

Вот ошибка, которую вы получите для случая (3):

System.AggregateException: A Task's exception(s) were not observed either by Waiting on the Task or accessing its Exception property. As a result, the unobserved exception was rethrown by the finalizer thread. ---> System.NullReferenceException: Object reference not set to an instance of an object.
   at System.Web.ThreadContext.AssociateWithCurrentThread(Boolean setImpersonationContext)
   at System.Web.HttpApplication.OnThreadEnterPrivate(Boolean setImpersonationContext)
   at System.Web.HttpApplication.System.Web.Util.ISyncContext.Enter()
   at System.Web.Util.SynchronizationHelper.SafeWrapCallback(Action action)
   at System.Threading.Tasks.Task.Execute()
   --- End of inner exception stack trace ---
---> (Inner Exception #0) System.NullReferenceException: Object reference not set to an instance of an object.
   at System.Web.ThreadContext.AssociateWithCurrentThread(Boolean setImpersonationContext)
   at System.Web.HttpApplication.OnThreadEnterPrivate(Boolean setImpersonationContext)
   at System.Web.HttpApplication.System.Web.Util.ISyncContext.Enter()
   at System.Web.Util.SynchronizationHelper.SafeWrapCallback(Action action)
   at System.Threading.Tasks.Task.Execute()<---

Для случая ( 2) вы получите аналогичную ошибку, но с исходной трассировкой стека исключений.

Для .NET 4.0 и более поздних версий вы можете поймать ненаблюдаемые исключения, используя TaskScheduler.UnobservedTaskException. Для .NET 4.5 и более поздних ненаблюдаемых исключений по умолчанию пропущено исключение unobserved .NET 4.0 приведет к сбою вашего процесса.

Подробнее здесь: Обработка исключений задач в .NET 4.5

47
задан Victor 23 August 2013 в 16:36
поделиться

2 ответа

Теперь в случае строки это не так, потому что строка войдет в пул строк, а JVM сохранит объект для повторного использования. Итак, это означает, что некогда созданная строка будет «никогда» не собираться мусором?

Во-первых, это только String литералы 1, которые получают автоматически интернирован / добавлен в пул строк. Строки, созданные приложением, не интернированы ... если ваше приложение явно не называет String.intern().

Во-вторых, на самом деле правила сбора мусора в пуле String такие же, как для других строк / другие объекты. Строки будут собирать мусор, если они когда-либо станут недоступными.

На практике объекты String, которые соответствуют строковым литералам обычно , не становятся кандидатами на сборку мусора. Это связано с тем, что имеется ссылка неявная ссылка на строковый объект в коде каждого метода, который использует литерал. Это означает, что String достижима до тех пор, пока метод может быть выполнен.

Однако это не всегда случай. Если литерал был определен в классе, который был динамически загружен (например, с помощью Class.forName(...)), тогда можно организовать, что класс разгружен . Если это произойдет, объект String для литерала будет недоступен и будет восстановлен, когда куча, содержащая интернированную строку, получит GC'ed.


1 - Неверно говорить, что все строковые литералы интернированы. Если строковый литерал появляется только в исходном коде в качестве подвыражения выражения константы (времени компиляции) ( JLS 15.28 ), то литерал не будет отображаться в файле «.class» в любой форме . Такой литерал не будет интернирован, потому что он не будет существовать во время выполнения.

54
ответ дан Stephen C 19 August 2018 в 12:44
поделиться
  • 1
    можем ли мы просто сказать, что строковые литералы (интернированные строки) не являются GC, если только класс, который их создал, и неинтерминированные String (созданные с использованием нового) являются GC, как любой другой объект, то есть когда нет ссылки на него? – sactiw 1 March 2016 в 07:36
  • 2
    Нет. Вы приравниваете интернированные строки строковыми литералами. Все строковые литералы являются интернированными строками, но не все интернированные строки являются строковыми литералами. – Stephen C 1 March 2016 в 08:03

Вы правы; строки в основном пуле никогда не будут GC'd.

Однако большинство строк не интернированы. Строковые литералы интернированы, а строки, переданные в String.intern(), интернированы, но все остальные строки не интернированы и могут быть GC'd в норме.

7
ответ дан SLaks 19 August 2018 в 12:44
поделиться
  • 1
    Но разве это не будет потреблять много памяти? Специально для больших программ, которые используют много строк? – Eng.Fouad 23 August 2013 в 16:40
  • 2
    Имейте в виду, что «литеральные строки» занимают память, потому что они фактически являются частью вашей программы. Они должны быть там, или ваша программа что-то упустит. – Hot Licks 23 August 2013 в 16:43
  • 3
    «строки в первом пуле никогда не будут GC'd». - Это неверно для современной JVM Hotspot. Это сложнее ... – Stephen C 23 August 2013 в 16:57
  • 4
    @Jaskey - Строка, которую вы только что создали с помощью new, не будет интернирована. Объект String, представляющий строковый литерал , будет интернирован. – Stephen C 22 August 2014 в 15:56
  • 5
    Обратите внимание: этот ответ устарел и не применяется к современным JVM. – Raman Sahasi 8 August 2018 в 07:24
Другие вопросы по тегам:

Похожие вопросы: